Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Vidam] Week 3 Solution | Go #81

Merged
merged 10 commits into from
May 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 83 additions & 0 deletions climbing-stairs/invidam.go.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# Intuition
<!-- Describe your first thoughts on how to solve this problem. -->
This problem is a typical dynamic programming (DP) problem. (keyword: `Fibonacci`)

DP has two methods: tabulation and memoization. I'll introduce both methods.
# Approach (tabulation)
<!-- Describe your approach to solving the problem. -->
1. Create an array to store the results.
2. Initiate default values for the base cases `0` and `1`.
3. While iterating through the array, fill in the values using this formula $$f(n) = f(n-1) + f(n-2)$$
# Complexity
## Complexity (V1)
- Time complexity: $$O(n)$$
<!-- Add your time complexity here, e.g. $$O(n)$$ -->

- Space complexity: $$O(n)$$
<!-- Add your space complexity here, e.g. $$O(n)$$ -->
# Complexity (V2)
- Time complexity: $$O(n)$$
<!-- Add your time complexity here, e.g. $$O(n)$$ -->

- Space complexity: $$O(1)$$
<!-- Add your space complexity here, e.g. $$O(n)$$ -->

(n is value of `n`)
# Code
```go
func climbStairsV1(n int) int {
climbData := make([]int, n+2, n+2)
climbData[0], climbData[1] = 1, 1
for s := 0; s < n; s++ {
climbData[s+2] = climbData[s] + climbData[s+1]
}

return climbData[n]
}

func climbStairsV2(n int) int {
prev, curr := 1, 1
for s := 1; s < n; s++ {
prev, curr = curr, prev+curr
}

return curr
}
```

> 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.

- - -

# Approach (memoization)
<!-- Describe your approach to solving the problem. -->
1. Create an hash map (or array) to **cache** the results.
2. Initialize default values to indicate unvisited nodes. (`-1`).
3. Call the recursion using this formula $$f(n) = f(n-1) + f(n-2)$$.
4. If there are cached results, return it.
5. Pay attension to the **base case**, and always update the cache.

# Complexity
- Time complexity: $$O(n)$$
<!-- Add your time complexity here, e.g. $$O(n)$$ -->

- Space complexity: $$O(n)$$
<!-- Add your space complexity here, e.g. $$O(n)$$ -->
(n is value of `n`)
# Code
```go
var cache map[int]int = map[int]int{}
func climbStairs(n int) int {
if n == 0 || n == 1 {
return 1
} else if n < 0 {
return 0
} else if val, ok := cache[n]; ok {
return val
}

ret := climbStairs(n-1) + climbStairs(n-2)
cache[n] = ret
return ret
}
```
75 changes: 75 additions & 0 deletions maximum-depth-of-binary-tree/invidam.go.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# Intuition
Recursuib is a natural method for iterating trees.

# Approach
<!-- Describe your approach to solving the problem. -->
1. Child function can calculate the depth of its subtrees automatically.
2. Parent function only select the maximum of the two depths and return +1. (i.e. `+1` means parent's depth.)

# Complexity
- Time complexity: $$O(n)$$
<!-- Add your time complexity here, e.g. $$O(n)$$ -->

- Space complexity
- $$O(logN)$$ (best case for balanced tree)
- $$O(N)$$ (worst case for skewed tree)
<!-- Add your space complexity here, e.g. $$O(n)$$ -->
(N: size of node.)
# Code
```
func maxDepth(root *TreeNode) int {
if root == nil {
return 0
}
return max(maxDepth(root.Left), maxDepth(root.Right)) + 1
}
```
- - -
# Intuition
Implement Queue can be troublesome, but it is effective to problem that require tracking depths or levels.
<!-- Describe your first thoughts on how to solve this problem. -->

# Approach
<!-- Describe your approach to solving the problem. -->
1. Maintain Element belonging to the same level in the queue.
2. While Iterating through the queue, remove the current level and save the next level.
- In GoLang, `range for loop` capture only first once. So We can maintain current level's easily.
3. increase depth while iterationg through all elements until the end.
# Complexity
- Time complexity: $$O(n)$$
<!-- Add your time complexity here, e.g. $$O(n)$$ -->

- Space complexity
- $$O(logN)$$ (best case for balanced tree)
- $$O(N)$$ (worst case for skewed tree)
<!-- Add your space complexity here, e.g. $$O(n)$$ -->
(N: size of node.)

# Code
```go
func maxDepth(root *TreeNode) int {
if root == nil {
return 0
}
depth := 0
currLevel := []*TreeNode{root}

for len(currLevel) != 0 {
depth++
for _, curr := range currLevel {
if curr.Left != nil {
currLevel = append(currLevel, curr.Left)
}
if curr.Right != nil {
currLevel = append(currLevel, curr.Right)
}
currLevel = currLevel[1:]
}
}

return depth
}
```

# What I learned
- [Slice](https://velog.io/@invidam/GoLang-Slice)
34 changes: 34 additions & 0 deletions meeting-rooms/invidam.go.md
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

고생하셨습니다! 요 파일 제외하고 나머지 파일들은 전부 코드언어 설정을 따로 안한 상태로 업로드 하셨는데 혹시 빼먹으신게 아닌가 싶어요!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

그러네요!! 밑에 코멘트까지 참고하여 담주부턴 반영하겠습니다~

감사해용

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

앗 leo님이 먼저 달아주셨었군요..! 못보고 추가로 말씀드려버렸네요...! ㅠㅠ

Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Intuition
It is a simple `greedy` problem.
간단한 그리디 분류의 문제다.
# Approach
1. To find earliest interval, sort intervals by start time in ascending order.
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.
# Complexity
- Time complexity: $$O(nlog(n))$$
- Space complexity: $$O(n)$$

(n is length of `intervals`)
# Code
```go
func CanAttendMeetings(intervals []*Interval) bool {
sort.Slice(intervals, func(i, j int) bool {
return intervals[i].Start < intervals[j].Start
})

curr := &Interval{-1, -1}
for _, next := range intervals {
if curr.End > next.Start {
return false
}
curr = next
}

return true
}
```

# What I learned
GoLang Sort
- mechanism: [Pattern-defeating Quicksort](https://www.youtube.com/watch?v=jz-PBiWwNjc)
- usage: https://hackthedeveloper.com/how-to-sort-in-go/
82 changes: 82 additions & 0 deletions same-tree/invidam.go.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# Intuition (DFS, Recursion)
<!-- Describe your first thoughts on how to solve this problem. -->
Recursion is natural method to iterate trees. (Particularly, multiple trees!)
# Approach
<!-- Describe your approach to solving the problem. -->
1. Child nodes(i.e. Left and Right) are compared eqaulity with their subtrees.
2. Parent nodes check their own values (`Val`) and their children's comparisions.

(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`)
# Complexity
- Time complexity: $$O(n+m)$$
<!-- Add your time complexity here, e.g. $$O(n)$$ -->

- Space complexity: $$O(h_n + h_m)$$
<!-- Add your space complexity here, e.g. $$O(n)$$ -->

(n and m are number of nodes in trees p and q. $$h_n$$ and $$h_m$$ are their heights.)
# Code
```go
func isSameTree(p *TreeNode, q *TreeNode) bool {
if p == nil || q == nil {
return p == nil && q == nil
}

return p.Val == q.Val && isSameTree(p.Left, q.Left) && isSameTree(p.Right, q.Right)
}
```
- - -
# BFS
# Approach
<!-- Describe your approach to solving the problem. -->
1. Like a typical BFS solution, Create Queue and iterate through the tree. However, in this case, mulitple queues are required.
2. While Iterating, Check equality two nodes in p and q.
# Complexity
- Time complexity: $$O(n+m)$$
<!-- Add your time complexity here, e.g. $$O(n)$$ -->

- Space complexity: $$O(n + m)$$
<!-- Add your space complexity here, e.g. $$O(n)$$ -->

(n and m are number of nodes in trees p and q.)
# Code
```go
func updateQueue(node *TreeNode, queue []*TreeNode) []*TreeNode {
queue = append(queue, node.Left)
queue = append(queue, node.Right)

return queue
}

func isSameTree(p *TreeNode, q *TreeNode) bool {
if p == nil || q == nil {
return p == nil && q == nil
}
pQueue := []*TreeNode{p}
qQueue := []*TreeNode{q}

for len(pQueue) != 0 {
pCurr := pQueue[0]
qCurr := qQueue[0]

pQueue = pQueue[1:]
qQueue = qQueue[1:]

if pCurr == nil && qCurr == nil {
continue
}

if (pCurr == nil || qCurr == nil) || (pCurr.Val != qCurr.Val) {
return false
}
pQueue = updateQueue(pCurr, pQueue)
qQueue = updateQueue(qCurr, qQueue)
}

return true
}
```

# What I learned
- Short circuit In Go.
- Function couldn't update original value (like `updateQueue()'s queue`)
105 changes: 105 additions & 0 deletions subtree-of-another-tree/invidam.go.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
# Intuition (DFS & BFS)
<!-- Describe your first thoughts on how to solve this problem. -->
We need two main function: one to check the equality of nodes and the subtrees, and another to iterate through the main tree.

We will use both DFS and BFS methods to solve this problem.

Reference. [Same Tree](ttps://leetcode.com/problems/same-tree/solutions/5159658/go-simple-solution)

# Approach
<!-- Describe your approach to solving the problem. -->
1. Create a function that, while iterating using DFS(Recursion) or BFS(Queue),checks if the two trees are equal.
2. First, check if the two trees are equal. If not, iterate through the children of main tree. (`root.Left`, `root.Right`)
# Complexity (DFS)
- Time complexity: $$O(n * m)$$
(This complexity is $$O(n * m)$$. because the `isSubtree()` iterates throuth all modes while **simultaneously** calling the `isEqualtree()` for each node.
<!-- Add your time complexity here, e.g. $$O(n)$$ -->

- Space complexity: $$O({h_n} + {h_m})$$
(This complexity is determined. because the maximun depth of the call stack, which doesn't exceed the sum of heights of both trees.)
<!-- Add your space complexity here, e.g. $$O(n)$$ -->

# Code
```
func isEqualTree(root *TreeNode, subRoot *TreeNode) bool {
if (root == nil) || (subRoot == nil) {
return root == subRoot
}

return (root.Val == subRoot.Val) && isEqualTree(root.Left, subRoot.Left) && isEqualTree(root.Right, subRoot.Right)
}

func isSubtree(root *TreeNode, subRoot *TreeNode) bool {
if root == nil {
//assert subRoot != nil
return false
}

return isEqualTree(root, subRoot) || isSubtree(root.Left, subRoot) || isSubtree(root.Right, subRoot)
}
```
- - -
# Complexity (BFS)
- Time complexity: $$O(n * m)$$
(This complexity is $$O(n * m)$$. because the `isSubtree()` iterates throuth all modes while **simultaneously** calling the `isEqualtree()` for each node.
<!-- Add your time complexity here, e.g. $$O(n)$$ -->

- Space complexity: $$O({h_n} + {h_m})$$
(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.)
<!-- Add your space complexity here, e.g. $$O(n)$$ -->
# Code
```go
func isEqualTree(root *TreeNode, subRoot *TreeNode) bool {
q1 := []*TreeNode{root}
q2 := []*TreeNode{subRoot}

for len(q1) != 0 {
f1 := q1[0]
f2 := q2[0]

q1 = q1[1:]
q2 = q2[1:]

if (f1 == nil) && (f2 == nil) {
continue
}
if (f1 == nil) || (f2 == nil) || (f1.Val != f2.Val) {
return false
}

q1 = append(q1, f1.Left)
q1 = append(q1, f1.Right)

q2 = append(q2, f2.Left)
q2 = append(q2, f2.Right)
}

return true
}

func isSubtree(root *TreeNode, subRoot *TreeNode) bool {
if root == nil {
//assert subRoot != nil
return false
}

q := []*TreeNode{root}

for len(q) != 0 {
node := q[0]
q = q[1:]

if node == nil {
continue
}
if isEqualTree(node, subRoot) {
return true
}

q = append(q, node.Left)
q = append(q, node.Right)
}

return false
}
```