-
Notifications
You must be signed in to change notification settings - Fork 126
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #591 from obzva/main
[Flynn] Week14
- Loading branch information
Showing
5 changed files
with
277 additions
and
0 deletions.
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,52 @@ | ||
/* | ||
풀이 | ||
- queue 자료구조를 사용하여 풀이합니다 | ||
Big O | ||
- N: 노드의 개수 | ||
- Time complexity: O(N) | ||
- 모든 노드를 조회합니다 | ||
- Space complexity: O(N) | ||
- 반환 결과값인 2차원 배열 levels -> O(N) | ||
- queue -> O(3/4 * N) = O(N) | ||
- 한 층이 가질 수 있는 최대 노드 개수는 약 N / 2 | ||
- queue의 크기가 가장 클 때는 두 층의 노드를 가지고 있으므로 N / 2 + (N / 2) / 2 개의 노드를 갖게 됨 | ||
- level -> O(N/2) = O(N) | ||
- - 한 층이 가질 수 있는 최대 노드 개수는 약 N / 2 | ||
*/ | ||
|
||
/** | ||
* Definition for a binary tree node. | ||
* type TreeNode struct { | ||
* Val int | ||
* Left *TreeNode | ||
* Right *TreeNode | ||
* } | ||
*/ | ||
func levelOrder(root *TreeNode) [][]int { | ||
levels := make([][]int, 0) | ||
|
||
if root == nil { | ||
return levels | ||
} | ||
|
||
queue := make([]*TreeNode, 0) | ||
queue = append(queue, root) | ||
for len(queue) > 0 { | ||
k := len(queue) | ||
level := make([]int, k) | ||
for i := 0; i < k; i++ { | ||
node := queue[i] | ||
level[i] = node.Val | ||
if node.Left != nil { | ||
queue = append(queue, node.Left) | ||
} | ||
if node.Right != nil { | ||
queue = append(queue, node.Right) | ||
} | ||
} | ||
queue = queue[k:] | ||
levels = append(levels, level) | ||
} | ||
|
||
return levels | ||
} |
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,51 @@ | ||
/* | ||
풀이 | ||
- house robber 문제와 비슷합니다 | ||
이전 풀이 링크: https://github.com/DaleStudy/leetcode-study/pull/576/files#diff-a98dce0d933d299b3b8e2cc345b95a398c894391b7b86b4b85e3c0aea9d0757f | ||
- 첫번째 집을 터는 경우와 안 터는 경우를 나누어 계산합니다 | ||
Big O | ||
- N: 주어진 배열 nums의 길이 | ||
- Time complexity: O(N) | ||
- Space complexity: O(1) | ||
*/ | ||
|
||
import "slices" | ||
|
||
func rob(nums []int) int { | ||
n := len(nums) | ||
|
||
if n < 4 { | ||
return slices.Max(nums) | ||
} else if n == 4 { | ||
return max(nums[0]+nums[2], nums[1]+nums[3]) | ||
} | ||
|
||
// rob nums[0] (can't rob nums[1] and nums[n-1]) | ||
robFirst := nums[0] | ||
ppRobbed := nums[2] // initial value = nums[2] because we can't rob nums[1] | ||
pRobbed := nums[3] | ||
pUnrobbed := nums[2] | ||
for i := 4; i < n-1; i++ { // i < n-1 because we can't rob nums[n-1] | ||
ppRobbed, pRobbed, pUnrobbed = pRobbed, nums[i]+max(ppRobbed, pUnrobbed), max(pRobbed, pUnrobbed) | ||
} | ||
robFirst += max(pRobbed, pUnrobbed) | ||
|
||
// skip nums[0] | ||
ppRobbed = nums[1] | ||
pRobbed = nums[2] | ||
pUnrobbed = nums[1] | ||
for i := 3; i < n; i++ { | ||
ppRobbed, pRobbed, pUnrobbed = pRobbed, nums[i]+max(ppRobbed, pUnrobbed), max(pRobbed, pUnrobbed) | ||
} | ||
skipFirst := max(pRobbed, pUnrobbed) | ||
|
||
return max(robFirst, skipFirst) | ||
} | ||
|
||
func max(a, b int) int { | ||
if a > b { | ||
return a | ||
} else { | ||
return b | ||
} | ||
} |
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,46 @@ | ||
/* | ||
풀이 | ||
- 회의의 시작시간과 종료시간을 각각 오름차순 정렬하여 풀이할 수 있습니다 | ||
Big O | ||
- N: 주어진 배열 intervals의 길이 | ||
- Time complexity: O(NlogN) | ||
- starts, ends 생성 -> O(N) | ||
- slices.Sort() -> O(NlogN) | ||
- 마지막 반복문 -> O(N) | ||
- Space complexity: O(logN) | ||
- Go의 slices.Sort()는 퀵소트를 이용하므로 재귀 호출 스택 깊이 O(logN)이 고려되어야 함 | ||
*/ | ||
|
||
import "slices" | ||
|
||
func minMeetingRooms(intervals [][]int) int { | ||
n := len(intervals) | ||
|
||
if n == 1 { | ||
return 1 | ||
} | ||
|
||
starts := make([]int, n) // 회의 시작시간들 | ||
ends := make([]int, n) // 회의 종료시간들 | ||
for i, interval := range intervals { | ||
starts[i] = interval[0] | ||
ends[i] = interval[1] | ||
} | ||
// 오름차순 정렬 | ||
slices.Sort(starts) | ||
slices.Sort(ends) | ||
|
||
rooms := 0 | ||
sPtr := 0 | ||
ePtr := 0 | ||
for sPtr < n { | ||
if starts[sPtr] < ends[ePtr] { // 현재 사용가능한 회의실이 없음 (현재 진행중인 모든 회의가 starts[sPtr]보다 큼) | ||
rooms++ // 새로운 회의실 추가함 | ||
} else { | ||
ePtr++ // 기존 회의실 중에 남는 방이 있음, 새로운 회의실 추가하지 않음 | ||
} | ||
sPtr++ | ||
} | ||
|
||
return rooms | ||
} |
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,29 @@ | ||
/* | ||
풀이 | ||
- 원본 uint32 num에 대하여 LSB부터(가장 오른쪽 bit) 탐색합니다 | ||
LSB % 2 == 1 -> uint32의 새로운 MSB에(가장 왼쪽 bit) 1 추가 | ||
else -> 0 추가 | ||
Big O | ||
- Time complexity: O(1) | ||
- input num에 상관 없이 32번의 반복을 고정적으로 실행합니다 | ||
- Space complexity: O(1) | ||
*/ | ||
|
||
func reverseBits(num uint32) uint32 { | ||
var res uint32 = 0 | ||
for i := 0; i < 32; i++ { | ||
// using numerical operators | ||
// if num % 2 == 1 { | ||
// res = res * 2 + 1 | ||
// } else { | ||
// res *= 2 | ||
// } | ||
// num /= 2 | ||
|
||
// using bitwise operators | ||
res = (res << 1) | (num & 1) | ||
num >>= 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,99 @@ | ||
/* | ||
풀이 | ||
- Trie 자료구조와 2차원 배열에서의 DFS & Backtracking을 사용하여 풀이할 수 있습니다 | ||
Big O | ||
- M, N: 주어진 2차원 배열 board의 행, 열 크기 | ||
- Max(W): 주어진 배열 words 중에서 가장 길이가 긴 단어의 길이 | ||
- Sum(W): 주어진 배열 words에 포함된 모든 단어의 길이의 총합 | ||
- Time complexity: O(Sum(W) + MN * Max(W)) | ||
- building trie: O(Sum(W)) | ||
- 각 단어의 모든 문자를 한 번씩 조회합니다 | ||
- 반복문: O(MN * Max(W)) | ||
- 행, 열에 대한 반복: O(MN) | ||
- dfs: O(Max(W)) | ||
- 한 좌표에 대해 dfs 함수를 trie의 최대 깊이, 즉 O(Max(W))만큼 호출합니다 | ||
- Space complexity: O(Sum(W) + Max(W)) | ||
- building trie: O(Sum(W)) at worst | ||
- dfs: O(Max(W)) | ||
- 재귀 호출 스택의 깊이를 고려해야 합니다 | ||
*/ | ||
|
||
func findWords(board [][]byte, words []string) []string { | ||
// building trie | ||
root := &trieNode{} | ||
for _, w := range words { | ||
root.add(w) | ||
} | ||
|
||
m := len(board) | ||
n := len(board[0]) | ||
res := make([]string, 0, len(words)) // create result | ||
for r := 0; r < m; r++ { | ||
for c := 0; c < n; c++ { | ||
if len(res) == len(words) { // early break if we found all the words | ||
break | ||
} | ||
if root.children[idx(board[r][c])] != nil { // dfs if you found starting letter of any words | ||
dfs(r, c, &board, root, &res) | ||
} | ||
} | ||
} | ||
|
||
return res | ||
} | ||
|
||
// ----- Implementation of TrieNode ----- | ||
type trieNode struct { | ||
children [26]*trieNode | ||
word string | ||
} | ||
|
||
func (t *trieNode) add(w string) { | ||
for i, c := range w { | ||
if t.children[c-'a'] == nil { // create new child node if there wasn't | ||
t.children[c-'a'] = &trieNode{} | ||
} | ||
t = t.children[c-'a'] | ||
if i == len(w)-1 { | ||
t.word = w | ||
} | ||
} | ||
} | ||
|
||
// ----- Dfs ----- | ||
func dfs(r, c int, board *[][]byte, parentNode *trieNode, res *[]string) { | ||
currLetter := (*board)[r][c] | ||
currNode := parentNode.children[idx(currLetter)] | ||
// if current trie node represents some word, then append it to the result | ||
if currNode.word != "" { | ||
*res = append(*res, currNode.word) | ||
currNode.word = "" // prevent duplicate words into the result | ||
} | ||
// mark current cell as visited | ||
(*board)[r][c] = '#' | ||
// search for the 4 directions | ||
m := len(*board) | ||
n := len((*board)[0]) | ||
dr := []int{0, 0, 1, -1} | ||
dc := []int{1, -1, 0, 0} | ||
for i := 0; i < 4; i++ { | ||
nr := r + dr[i] | ||
nc := c + dc[i] | ||
if !(0 <= nr && nr < m) || !(0 <= nc && nc < n) { // skip the invalid coordinates | ||
continue | ||
} | ||
if (*board)[nr][nc] == '#' { // skip the visited cell | ||
continue | ||
} | ||
if currNode.children[idx((*board)[nr][nc])] != nil { | ||
dfs(nr, nc, board, currNode, res) | ||
} | ||
} | ||
// restore the cell | ||
(*board)[r][c] = currLetter | ||
} | ||
|
||
// ----- Helper ----- | ||
func idx(b byte) int { | ||
return int(b - 'a') | ||
} |