Skip to content

Commit 5063d27

Browse files
authored
Merge pull request DaleStudy#81 from Invidam/week03-invidam
[Vidam] Week 3 Solution | Go
2 parents 174d25e + 7ae7990 commit 5063d27

File tree

5 files changed

+379
-0
lines changed

5 files changed

+379
-0
lines changed

climbing-stairs/invidam.go.md

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
# Intuition
2+
<!-- Describe your first thoughts on how to solve this problem. -->
3+
This problem is a typical dynamic programming (DP) problem. (keyword: `Fibonacci`)
4+
5+
DP has two methods: tabulation and memoization. I'll introduce both methods.
6+
# Approach (tabulation)
7+
<!-- Describe your approach to solving the problem. -->
8+
1. Create an array to store the results.
9+
2. Initiate default values for the base cases `0` and `1`.
10+
3. While iterating through the array, fill in the values using this formula $$f(n) = f(n-1) + f(n-2)$$
11+
# Complexity
12+
## Complexity (V1)
13+
- Time complexity: $$O(n)$$
14+
<!-- Add your time complexity here, e.g. $$O(n)$$ -->
15+
16+
- Space complexity: $$O(n)$$
17+
<!-- Add your space complexity here, e.g. $$O(n)$$ -->
18+
# Complexity (V2)
19+
- Time complexity: $$O(n)$$
20+
<!-- Add your time complexity here, e.g. $$O(n)$$ -->
21+
22+
- Space complexity: $$O(1)$$
23+
<!-- Add your space complexity here, e.g. $$O(n)$$ -->
24+
25+
(n is value of `n`)
26+
# Code
27+
```go
28+
func climbStairsV1(n int) int {
29+
climbData := make([]int, n+2, n+2)
30+
climbData[0], climbData[1] = 1, 1
31+
for s := 0; s < n; s++ {
32+
climbData[s+2] = climbData[s] + climbData[s+1]
33+
}
34+
35+
return climbData[n]
36+
}
37+
38+
func climbStairsV2(n int) int {
39+
prev, curr := 1, 1
40+
for s := 1; s < n; s++ {
41+
prev, curr = curr, prev+curr
42+
}
43+
44+
return curr
45+
}
46+
```
47+
48+
> As you can see in `V2`, it can be optimized. Remove the array and maintain only the `prev` and `curr` values. In Golang, `Multiple Assignment` prodives syntatic sugar.
49+
50+
- - -
51+
52+
# Approach (memoization)
53+
<!-- Describe your approach to solving the problem. -->
54+
1. Create an hash map (or array) to **cache** the results.
55+
2. Initialize default values to indicate unvisited nodes. (`-1`).
56+
3. Call the recursion using this formula $$f(n) = f(n-1) + f(n-2)$$.
57+
4. If there are cached results, return it.
58+
5. Pay attension to the **base case**, and always update the cache.
59+
60+
# Complexity
61+
- Time complexity: $$O(n)$$
62+
<!-- Add your time complexity here, e.g. $$O(n)$$ -->
63+
64+
- Space complexity: $$O(n)$$
65+
<!-- Add your space complexity here, e.g. $$O(n)$$ -->
66+
(n is value of `n`)
67+
# Code
68+
```go
69+
var cache map[int]int = map[int]int{}
70+
func climbStairs(n int) int {
71+
if n == 0 || n == 1 {
72+
return 1
73+
} else if n < 0 {
74+
return 0
75+
} else if val, ok := cache[n]; ok {
76+
return val
77+
}
78+
79+
ret := climbStairs(n-1) + climbStairs(n-2)
80+
cache[n] = ret
81+
return ret
82+
}
83+
```
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
# Intuition
2+
Recursuib is a natural method for iterating trees.
3+
4+
# Approach
5+
<!-- Describe your approach to solving the problem. -->
6+
1. Child function can calculate the depth of its subtrees automatically.
7+
2. Parent function only select the maximum of the two depths and return +1. (i.e. `+1` means parent's depth.)
8+
9+
# Complexity
10+
- Time complexity: $$O(n)$$
11+
<!-- Add your time complexity here, e.g. $$O(n)$$ -->
12+
13+
- Space complexity
14+
- $$O(logN)$$ (best case for balanced tree)
15+
- $$O(N)$$ (worst case for skewed tree)
16+
<!-- Add your space complexity here, e.g. $$O(n)$$ -->
17+
(N: size of node.)
18+
# Code
19+
```
20+
func maxDepth(root *TreeNode) int {
21+
if root == nil {
22+
return 0
23+
}
24+
return max(maxDepth(root.Left), maxDepth(root.Right)) + 1
25+
}
26+
```
27+
- - -
28+
# Intuition
29+
Implement Queue can be troublesome, but it is effective to problem that require tracking depths or levels.
30+
<!-- Describe your first thoughts on how to solve this problem. -->
31+
32+
# Approach
33+
<!-- Describe your approach to solving the problem. -->
34+
1. Maintain Element belonging to the same level in the queue.
35+
2. While Iterating through the queue, remove the current level and save the next level.
36+
- In GoLang, `range for loop` capture only first once. So We can maintain current level's easily.
37+
3. increase depth while iterationg through all elements until the end.
38+
# Complexity
39+
- Time complexity: $$O(n)$$
40+
<!-- Add your time complexity here, e.g. $$O(n)$$ -->
41+
42+
- Space complexity
43+
- $$O(logN)$$ (best case for balanced tree)
44+
- $$O(N)$$ (worst case for skewed tree)
45+
<!-- Add your space complexity here, e.g. $$O(n)$$ -->
46+
(N: size of node.)
47+
48+
# Code
49+
```go
50+
func maxDepth(root *TreeNode) int {
51+
if root == nil {
52+
return 0
53+
}
54+
depth := 0
55+
currLevel := []*TreeNode{root}
56+
57+
for len(currLevel) != 0 {
58+
depth++
59+
for _, curr := range currLevel {
60+
if curr.Left != nil {
61+
currLevel = append(currLevel, curr.Left)
62+
}
63+
if curr.Right != nil {
64+
currLevel = append(currLevel, curr.Right)
65+
}
66+
currLevel = currLevel[1:]
67+
}
68+
}
69+
70+
return depth
71+
}
72+
```
73+
74+
# What I learned
75+
- [Slice](https://velog.io/@invidam/GoLang-Slice)

meeting-rooms/invidam.go.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# Intuition
2+
It is a simple `greedy` problem.
3+
간단한 그리디 분류의 문제다.
4+
# Approach
5+
1. To find earliest interval, sort intervals by start time in ascending order.
6+
2. After sorting, while iterating through the array, check for conflict: the current interval's start time shoud be smaller than the next interval's end time.
7+
# Complexity
8+
- Time complexity: $$O(nlog(n))$$
9+
- Space complexity: $$O(n)$$
10+
11+
(n is length of `intervals`)
12+
# Code
13+
```go
14+
func CanAttendMeetings(intervals []*Interval) bool {
15+
sort.Slice(intervals, func(i, j int) bool {
16+
return intervals[i].Start < intervals[j].Start
17+
})
18+
19+
curr := &Interval{-1, -1}
20+
for _, next := range intervals {
21+
if curr.End > next.Start {
22+
return false
23+
}
24+
curr = next
25+
}
26+
27+
return true
28+
}
29+
```
30+
31+
# What I learned
32+
GoLang Sort
33+
- mechanism: [Pattern-defeating Quicksort](https://www.youtube.com/watch?v=jz-PBiWwNjc)
34+
- usage: https://hackthedeveloper.com/how-to-sort-in-go/

same-tree/invidam.go.md

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
# Intuition (DFS, Recursion)
2+
<!-- Describe your first thoughts on how to solve this problem. -->
3+
Recursion is natural method to iterate trees. (Particularly, multiple trees!)
4+
# Approach
5+
<!-- Describe your approach to solving the problem. -->
6+
1. Child nodes(i.e. Left and Right) are compared eqaulity with their subtrees.
7+
2. Parent nodes check their own values (`Val`) and their children's comparisions.
8+
9+
(Tip: Comparing the values of nodes before recursion is more efficient. due to **short circuit**, which stops further evaluation(`isSameTree(p.Left, q.Left) && isSameTree(p.Right, q.Right)`) when the outcome is already determined by comparing `p.Val == q.Val`)
10+
# Complexity
11+
- Time complexity: $$O(n+m)$$
12+
<!-- Add your time complexity here, e.g. $$O(n)$$ -->
13+
14+
- Space complexity: $$O(h_n + h_m)$$
15+
<!-- Add your space complexity here, e.g. $$O(n)$$ -->
16+
17+
(n and m are number of nodes in trees p and q. $$h_n$$ and $$h_m$$ are their heights.)
18+
# Code
19+
```go
20+
func isSameTree(p *TreeNode, q *TreeNode) bool {
21+
if p == nil || q == nil {
22+
return p == nil && q == nil
23+
}
24+
25+
return p.Val == q.Val && isSameTree(p.Left, q.Left) && isSameTree(p.Right, q.Right)
26+
}
27+
```
28+
- - -
29+
# BFS
30+
# Approach
31+
<!-- Describe your approach to solving the problem. -->
32+
1. Like a typical BFS solution, Create Queue and iterate through the tree. However, in this case, mulitple queues are required.
33+
2. While Iterating, Check equality two nodes in p and q.
34+
# Complexity
35+
- Time complexity: $$O(n+m)$$
36+
<!-- Add your time complexity here, e.g. $$O(n)$$ -->
37+
38+
- Space complexity: $$O(n + m)$$
39+
<!-- Add your space complexity here, e.g. $$O(n)$$ -->
40+
41+
(n and m are number of nodes in trees p and q.)
42+
# Code
43+
```go
44+
func updateQueue(node *TreeNode, queue []*TreeNode) []*TreeNode {
45+
queue = append(queue, node.Left)
46+
queue = append(queue, node.Right)
47+
48+
return queue
49+
}
50+
51+
func isSameTree(p *TreeNode, q *TreeNode) bool {
52+
if p == nil || q == nil {
53+
return p == nil && q == nil
54+
}
55+
pQueue := []*TreeNode{p}
56+
qQueue := []*TreeNode{q}
57+
58+
for len(pQueue) != 0 {
59+
pCurr := pQueue[0]
60+
qCurr := qQueue[0]
61+
62+
pQueue = pQueue[1:]
63+
qQueue = qQueue[1:]
64+
65+
if pCurr == nil && qCurr == nil {
66+
continue
67+
}
68+
69+
if (pCurr == nil || qCurr == nil) || (pCurr.Val != qCurr.Val) {
70+
return false
71+
}
72+
pQueue = updateQueue(pCurr, pQueue)
73+
qQueue = updateQueue(qCurr, qQueue)
74+
}
75+
76+
return true
77+
}
78+
```
79+
80+
# What I learned
81+
- Short circuit In Go.
82+
- Function couldn't update original value (like `updateQueue()'s queue`)

subtree-of-another-tree/invidam.go.md

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
# Intuition (DFS & BFS)
2+
<!-- Describe your first thoughts on how to solve this problem. -->
3+
We need two main function: one to check the equality of nodes and the subtrees, and another to iterate through the main tree.
4+
5+
We will use both DFS and BFS methods to solve this problem.
6+
7+
Reference. [Same Tree](ttps://leetcode.com/problems/same-tree/solutions/5159658/go-simple-solution)
8+
9+
# Approach
10+
<!-- Describe your approach to solving the problem. -->
11+
1. Create a function that, while iterating using DFS(Recursion) or BFS(Queue),checks if the two trees are equal.
12+
2. First, check if the two trees are equal. If not, iterate through the children of main tree. (`root.Left`, `root.Right`)
13+
# Complexity (DFS)
14+
- Time complexity: $$O(n * m)$$
15+
(This complexity is $$O(n * m)$$. because the `isSubtree()` iterates throuth all modes while **simultaneously** calling the `isEqualtree()` for each node.
16+
<!-- Add your time complexity here, e.g. $$O(n)$$ -->
17+
18+
- Space complexity: $$O({h_n} + {h_m})$$
19+
(This complexity is determined. because the maximun depth of the call stack, which doesn't exceed the sum of heights of both trees.)
20+
<!-- Add your space complexity here, e.g. $$O(n)$$ -->
21+
22+
# Code
23+
```
24+
func isEqualTree(root *TreeNode, subRoot *TreeNode) bool {
25+
if (root == nil) || (subRoot == nil) {
26+
return root == subRoot
27+
}
28+
29+
return (root.Val == subRoot.Val) && isEqualTree(root.Left, subRoot.Left) && isEqualTree(root.Right, subRoot.Right)
30+
}
31+
32+
func isSubtree(root *TreeNode, subRoot *TreeNode) bool {
33+
if root == nil {
34+
//assert subRoot != nil
35+
return false
36+
}
37+
38+
return isEqualTree(root, subRoot) || isSubtree(root.Left, subRoot) || isSubtree(root.Right, subRoot)
39+
}
40+
```
41+
- - -
42+
# Complexity (BFS)
43+
- Time complexity: $$O(n * m)$$
44+
(This complexity is $$O(n * m)$$. because the `isSubtree()` iterates throuth all modes while **simultaneously** calling the `isEqualtree()` for each node.
45+
<!-- Add your time complexity here, e.g. $$O(n)$$ -->
46+
47+
- Space complexity: $$O({h_n} + {h_m})$$
48+
(This complexity is determined. because the maximun sizes of the queues (`q`, `q1`, `q2`), which doesn't exceed the sum of sizes of both trees.)
49+
<!-- Add your space complexity here, e.g. $$O(n)$$ -->
50+
# Code
51+
```go
52+
func isEqualTree(root *TreeNode, subRoot *TreeNode) bool {
53+
q1 := []*TreeNode{root}
54+
q2 := []*TreeNode{subRoot}
55+
56+
for len(q1) != 0 {
57+
f1 := q1[0]
58+
f2 := q2[0]
59+
60+
q1 = q1[1:]
61+
q2 = q2[1:]
62+
63+
if (f1 == nil) && (f2 == nil) {
64+
continue
65+
}
66+
if (f1 == nil) || (f2 == nil) || (f1.Val != f2.Val) {
67+
return false
68+
}
69+
70+
q1 = append(q1, f1.Left)
71+
q1 = append(q1, f1.Right)
72+
73+
q2 = append(q2, f2.Left)
74+
q2 = append(q2, f2.Right)
75+
}
76+
77+
return true
78+
}
79+
80+
func isSubtree(root *TreeNode, subRoot *TreeNode) bool {
81+
if root == nil {
82+
//assert subRoot != nil
83+
return false
84+
}
85+
86+
q := []*TreeNode{root}
87+
88+
for len(q) != 0 {
89+
node := q[0]
90+
q = q[1:]
91+
92+
if node == nil {
93+
continue
94+
}
95+
if isEqualTree(node, subRoot) {
96+
return true
97+
}
98+
99+
q = append(q, node.Left)
100+
q = append(q, node.Right)
101+
}
102+
103+
return false
104+
}
105+
```

0 commit comments

Comments
 (0)