-
Notifications
You must be signed in to change notification settings - Fork 126
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
[Flynn] week 11 #548
Merged
Merged
[Flynn] week 11 #548
Changes from 3 commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
/* | ||
풀이 | ||
- post order traversal dfs를 활용하여 풀이할 수 있습니다 | ||
Big O | ||
- N: node의 개수 | ||
- H: Tree의 높이 | ||
- Time compleixty: O(N) | ||
- 모든 node를 최대 한 번 탐색합니다 | ||
- Space complexity: O(H) | ||
- 재귀 호출 스택의 깊이는 H에 비례하여 증가합니다 | ||
*/ | ||
|
||
/** | ||
* Definition for a binary tree node. | ||
* type TreeNode struct { | ||
* Val int | ||
* Left *TreeNode | ||
* Right *TreeNode | ||
* } | ||
*/ | ||
func maxPathSum(root *TreeNode) int { | ||
res := root.Val | ||
|
||
var maxSubtreeSum func(*TreeNode) int | ||
maxSubtreeSum = func(node *TreeNode) int { | ||
// base case | ||
if node == nil { | ||
return 0 | ||
} | ||
// left subtree로 내려갔을 때 구할 수 있는 maximum path sum | ||
// left subtree로 path를 내려갔을 때, left subtree가 sum에 기여하는 값이 0보다 작을 경우 | ||
// left subtree로는 path를 내려가지 않는 것이 좋음 | ||
// 따라서 left < 0 인 경우엔 left = 0 | ||
left := maxSubtreeSum(node.Left) | ||
if left < 0 { | ||
left = 0 | ||
} | ||
// right subtree도 left subtree와 동일함 | ||
right := maxSubtreeSum(node.Right) | ||
if right < 0 { | ||
right = 0 | ||
} | ||
// 현재 탐색하고 있는 node의 조상 node를 path에 포함하지 않고도 | ||
// maxPathSum이 구해지는 경우가 있음 | ||
if res < left+right+node.Val { | ||
res = left + right + node.Val | ||
} | ||
// 현재까지 계산한 subtree path sum을 부모 node에게 전달해야 함 | ||
// 현재 node의 부모와 이어지는 path여야 하므로, node.Val + max(left, right)를 반환하면 됨 | ||
subTreeSum := node.Val | ||
if left > right { | ||
subTreeSum += left | ||
} else { | ||
subTreeSum += right | ||
} | ||
return subTreeSum | ||
} | ||
|
||
maxSubtreeSum(root) | ||
return res | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
/* | ||
풀이 | ||
- valid tree인지 판별하는 문제입니다 | ||
주어진 input이 valid tree이려면, | ||
1. cycle이 없어야 합니다 (cycle이 있는 경우: [[0, 1], [1, 2], [2, 0]]) | ||
2. 모든 node가 연결되어 있어야 합니다 (모든 node가 연결되지 않은 경우: [[0, 1], [2, 3]]) | ||
- dfs 방식의 함수를 재귀 호출하여 풀이할 수 있습니다 | ||
Big O | ||
- N: n | ||
- E: 주어진 배열 edges의 크기 | ||
- Time complexity: O(N) | ||
- 모든 node를 최대 1번씩 탐색합니다 | ||
- Space complexity: O(E + N) | ||
- visited의 크기는 N에 비례하여 증가합니다 -> O(N) | ||
- adj의 크기는 E에 비례하여 증가합니다 -> O(E) | ||
- dfs의 재귀호출 스택 깊이는 최악의 경우 N까지 커질 수 있습니다 -> O(N) | ||
*/ | ||
|
||
func validTree(n int, edges [][]int) bool { | ||
// valid tree는 n-1개의 edge를 가질 수 밖에 없습validTree | ||
// 아래 판별식을 이용하면 유효하지 않은 input에 대해 상당한 연산을 줄일 수 있습니다 | ||
if len(edges) != n-1 { | ||
return false | ||
} | ||
// 주어진 2차원 배열 edges를 이용해 adjacency list를 생성합니다 | ||
adj := make([][]int, n) | ||
for _, edge := range edges { | ||
adj[edge[0]] = append(adj[edge[0]], edge[1]) | ||
adj[edge[1]] = append(adj[edge[1]], edge[0]) | ||
} | ||
// cycle이 있는지 여부를 판단하기 위해 visited라는 map을 생성합니다 (Go에서는 map으로 set 기능을 대신함) | ||
visited := make(map[int]bool) | ||
|
||
var dfs func(int, int) bool | ||
dfs = func(node int, parent int) bool { | ||
// cycle 발견시 false return | ||
if _, ok := visited[node]; ok { | ||
return false | ||
} | ||
visited[node] = true | ||
for _, next := range adj[node] { | ||
if next == parent { | ||
continue | ||
} | ||
if !dfs(next, node) { | ||
return false | ||
} | ||
} | ||
return true | ||
} | ||
// cycle 여부를 판단합니다 | ||
if !dfs(0, -1) { | ||
return false | ||
} | ||
// node가 모두 연결되어 있는지 여부를 판단합니다 | ||
return len(visited) == n | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
/* | ||
풀이 | ||
- newInterval의 start와 end에 대해 각각 이진탐색을 진행하여 insert할 index를 찾아낼 수 있습니다 | ||
- index의 앞뒤 interval과 newInterval을 비교하여 merge 여부를 판별하면 문제에서 원하는 배열을 만들 수 있습니다 | ||
Big O | ||
- N: 주어진 배열 intervals의 길이 | ||
- Time complexity: O(N) | ||
- 이진 탐색 -> O(logN) | ||
- append(res, ...) -> O(N) | ||
- O(N + logN) = O(N) | ||
- Space complexity: O(N) | ||
- 반환하는 배열 res의 공간 복잡도를 고려하면 O(N) | ||
*/ | ||
|
||
func insert(intervals [][]int, newInterval []int) [][]int { | ||
n := len(intervals) | ||
// base case | ||
if n == 0 { | ||
return append(intervals, newInterval) | ||
} | ||
// 이진탐색 함수 | ||
// isStart: newInterval의 start를 탐색할 땐 true, end를 탐색할 땐 false | ||
// target보다 큰 값 중에서 가장 작은 index를 반환함 | ||
var binarySearch func(int, bool) int | ||
binarySearch = func(target int, isStart bool) int { | ||
lo := 0 | ||
hi := len(intervals) | ||
for lo < hi { | ||
mid := lo + (hi-lo)/2 | ||
if isStart { | ||
if intervals[mid][0] < target { | ||
lo = mid + 1 | ||
} else { | ||
hi = mid | ||
} | ||
} else { | ||
if intervals[mid][1] < target { | ||
lo = mid + 1 | ||
} else { | ||
hi = mid | ||
} | ||
} | ||
} | ||
return lo | ||
} | ||
|
||
start := binarySearch(newInterval[0], true) | ||
// newInterval의 시작 지점이 intervals[start-1]의 끝 지점보다 작거나 같으면 merge해야 함 | ||
mergeStart := start > 0 && newInterval[0] <= intervals[start-1][1] | ||
end := binarySearch(newInterval[1], false) - 1 | ||
// newInterval의 끝 지점이 intervals[end+1]의 시작 지점보다 크거나 같으면 merge해야 함 | ||
mergeEnd := end+1 < n && newInterval[1] >= intervals[end+1][0] | ||
|
||
// -Go에서의 최적화를 위한 코드입니다- | ||
resCapacity := n + 1 | ||
if mergeStart { | ||
resCapacity-- | ||
} | ||
if mergeEnd { | ||
resCapacity-- | ||
} | ||
// ----------------------------- | ||
res := make([][]int, 0, resCapacity) | ||
// newInterval이 들어갈 index보다 앞 부분의 값들을 res에 append | ||
if mergeStart { | ||
res = append(res, intervals[:start-1]...) | ||
} else { | ||
res = append(res, intervals[:start]...) | ||
} | ||
// newInterval을 res에 append | ||
// mergeStart, mergeEnd 여부에 따라 병합할지 그대로 넣을지 판단 | ||
if mergeStart && mergeEnd { | ||
res = append(res, []int{intervals[start-1][0], intervals[end+1][1]}) | ||
} else if mergeStart { | ||
res = append(res, []int{intervals[start-1][0], newInterval[1]}) | ||
} else if mergeEnd { | ||
res = append(res, []int{newInterval[0], intervals[end+1][1]}) | ||
} else { | ||
res = append(res, newInterval) | ||
} | ||
// newInterval이 들어갈 index보다 뒷 부분의 값들을 res에 append | ||
if mergeEnd { | ||
res = append(res, intervals[end+2:]...) | ||
} else { | ||
res = append(res, intervals[end+1:]...) | ||
} | ||
|
||
return res | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
/* | ||
풀이 | ||
- DFS | ||
Big O | ||
- N: 노드의 개수 | ||
- H: 트리의 높이 | ||
- Time complexity: O(N) | ||
- 모든 노드를 탐색합니다 | ||
- Space complexity: O(H) | ||
- 재귀호출 스택의 크기는 트리의 높이에 비례하여 증가합니다 | ||
*/ | ||
|
||
/** | ||
* Definition for a binary tree node. | ||
* type TreeNode struct { | ||
* Val int | ||
* Left *TreeNode | ||
* Right *TreeNode | ||
* } | ||
*/ | ||
func maxDepth(root *TreeNode) int { | ||
maxDepth := 0 | ||
var dig func(*TreeNode, int) | ||
dig = func(node *TreeNode, depth int) { | ||
if node == nil { | ||
if maxDepth < depth { | ||
maxDepth = depth | ||
} | ||
return | ||
} | ||
dig(node.Left, depth+1) | ||
dig(node.Right, depth+1) | ||
} | ||
dig(root, 0) | ||
return maxDepth | ||
} | ||
|
||
/* | ||
풀이 | ||
- BFS | ||
Big O | ||
- N: 노드의 개수 | ||
- Time complexity: O(N) | ||
- 모든 노드를 탐색합니다 | ||
- Space complexity: O(N) | ||
- 노드 N개 짜리 트리에서 한 층의 폭은 N을 넘지 않습니다 | ||
따라서 queue의 공간복잡도는 O(N)입니다 | ||
*/ | ||
|
||
/** | ||
* Definition for a binary tree node. | ||
* type TreeNode struct { | ||
* Val int | ||
* Left *TreeNode | ||
* Right *TreeNode | ||
* } | ||
*/ | ||
func maxDepth(root *TreeNode) int { | ||
level := 0 | ||
queue := make([]*TreeNode, 0) | ||
if root != nil { | ||
queue = append(queue, root) | ||
level++ | ||
} | ||
for len(queue) > 0 { | ||
currQSize := len(queue) | ||
for currQSize > 0 { | ||
node := queue[0] | ||
queue = queue[1:] | ||
currQSize-- | ||
if node.Left != nil { | ||
queue = append(queue, node.Left) | ||
} | ||
if node.Right != nil { | ||
queue = append(queue, node.Right) | ||
} | ||
} | ||
if len(queue) > 0 { | ||
level++ | ||
} | ||
} | ||
return level | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
/** | ||
* Definition for singly-linked list. | ||
* type ListNode struct { | ||
* Val int | ||
* Next *ListNode | ||
* } | ||
*/ | ||
func reorderList(head *ListNode) { | ||
// find a middle node | ||
slow, fast := head, head | ||
for fast != nil && fast.Next != nil { | ||
slow = slow.Next | ||
fast = fast.Next.Next | ||
} | ||
// reverse the second part of the list | ||
var prev, curr *ListNode = nil, slow | ||
for curr != nil { | ||
tmp := curr.Next | ||
curr.Next = prev | ||
prev = curr | ||
curr = tmp | ||
} | ||
// merge two parts of the list | ||
curr1, curr2 := head, prev | ||
for curr2.Next != nil { | ||
tmp := curr1.Next | ||
curr1.Next = curr2 | ||
curr1 = tmp | ||
tmp = curr2.Next | ||
curr2.Next = curr1 | ||
curr2 = tmp | ||
} | ||
} |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for curr1, curr2 := head, prev; curr2 != nil && curr2.Next != nil; { tmp1, tmp2 := curr1.Next, curr2.Next curr1.Next, curr2.Next = curr2, tmp1 curr1, curr2 = tmp1, tmp2 }
별 차이는 없지만 마지막 부분 이렇게 바꿀수도 있지 않을까 싶어서 남겨봅니다 :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
감사합니다 훨씬 가독성이 좋네요 :)
바로 반영할게요