Skip to content

Commit c21e238

Browse files
authored
Merge pull request #591 from obzva/main
[Flynn] Week14
2 parents e6551e4 + 369dc9a commit c21e238

File tree

5 files changed

+277
-0
lines changed

5 files changed

+277
-0
lines changed
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
풀이
3+
- queue 자료구조를 사용하여 풀이합니다
4+
Big O
5+
- N: 노드의 개수
6+
- Time complexity: O(N)
7+
- 모든 노드를 조회합니다
8+
- Space complexity: O(N)
9+
- 반환 결과값인 2차원 배열 levels -> O(N)
10+
- queue -> O(3/4 * N) = O(N)
11+
- 한 층이 가질 수 있는 최대 노드 개수는 약 N / 2
12+
- queue의 크기가 가장 클 때는 두 층의 노드를 가지고 있으므로 N / 2 + (N / 2) / 2 개의 노드를 갖게 됨
13+
- level -> O(N/2) = O(N)
14+
- - 한 층이 가질 수 있는 최대 노드 개수는 약 N / 2
15+
*/
16+
17+
/**
18+
* Definition for a binary tree node.
19+
* type TreeNode struct {
20+
* Val int
21+
* Left *TreeNode
22+
* Right *TreeNode
23+
* }
24+
*/
25+
func levelOrder(root *TreeNode) [][]int {
26+
levels := make([][]int, 0)
27+
28+
if root == nil {
29+
return levels
30+
}
31+
32+
queue := make([]*TreeNode, 0)
33+
queue = append(queue, root)
34+
for len(queue) > 0 {
35+
k := len(queue)
36+
level := make([]int, k)
37+
for i := 0; i < k; i++ {
38+
node := queue[i]
39+
level[i] = node.Val
40+
if node.Left != nil {
41+
queue = append(queue, node.Left)
42+
}
43+
if node.Right != nil {
44+
queue = append(queue, node.Right)
45+
}
46+
}
47+
queue = queue[k:]
48+
levels = append(levels, level)
49+
}
50+
51+
return levels
52+
}

house-robber-ii/flynn.go

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*
2+
풀이
3+
- house robber 문제와 비슷합니다
4+
이전 풀이 링크: https://github.com/DaleStudy/leetcode-study/pull/576/files#diff-a98dce0d933d299b3b8e2cc345b95a398c894391b7b86b4b85e3c0aea9d0757f
5+
- 첫번째 집을 터는 경우와 안 터는 경우를 나누어 계산합니다
6+
Big O
7+
- N: 주어진 배열 nums의 길이
8+
- Time complexity: O(N)
9+
- Space complexity: O(1)
10+
*/
11+
12+
import "slices"
13+
14+
func rob(nums []int) int {
15+
n := len(nums)
16+
17+
if n < 4 {
18+
return slices.Max(nums)
19+
} else if n == 4 {
20+
return max(nums[0]+nums[2], nums[1]+nums[3])
21+
}
22+
23+
// rob nums[0] (can't rob nums[1] and nums[n-1])
24+
robFirst := nums[0]
25+
ppRobbed := nums[2] // initial value = nums[2] because we can't rob nums[1]
26+
pRobbed := nums[3]
27+
pUnrobbed := nums[2]
28+
for i := 4; i < n-1; i++ { // i < n-1 because we can't rob nums[n-1]
29+
ppRobbed, pRobbed, pUnrobbed = pRobbed, nums[i]+max(ppRobbed, pUnrobbed), max(pRobbed, pUnrobbed)
30+
}
31+
robFirst += max(pRobbed, pUnrobbed)
32+
33+
// skip nums[0]
34+
ppRobbed = nums[1]
35+
pRobbed = nums[2]
36+
pUnrobbed = nums[1]
37+
for i := 3; i < n; i++ {
38+
ppRobbed, pRobbed, pUnrobbed = pRobbed, nums[i]+max(ppRobbed, pUnrobbed), max(pRobbed, pUnrobbed)
39+
}
40+
skipFirst := max(pRobbed, pUnrobbed)
41+
42+
return max(robFirst, skipFirst)
43+
}
44+
45+
func max(a, b int) int {
46+
if a > b {
47+
return a
48+
} else {
49+
return b
50+
}
51+
}

meeting-rooms-ii/flynn.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
풀이
3+
- 회의의 시작시간과 종료시간을 각각 오름차순 정렬하여 풀이할 수 있습니다
4+
Big O
5+
- N: 주어진 배열 intervals의 길이
6+
- Time complexity: O(NlogN)
7+
- starts, ends 생성 -> O(N)
8+
- slices.Sort() -> O(NlogN)
9+
- 마지막 반복문 -> O(N)
10+
- Space complexity: O(logN)
11+
- Go의 slices.Sort()는 퀵소트를 이용하므로 재귀 호출 스택 깊이 O(logN)이 고려되어야 함
12+
*/
13+
14+
import "slices"
15+
16+
func minMeetingRooms(intervals [][]int) int {
17+
n := len(intervals)
18+
19+
if n == 1 {
20+
return 1
21+
}
22+
23+
starts := make([]int, n) // 회의 시작시간들
24+
ends := make([]int, n) // 회의 종료시간들
25+
for i, interval := range intervals {
26+
starts[i] = interval[0]
27+
ends[i] = interval[1]
28+
}
29+
// 오름차순 정렬
30+
slices.Sort(starts)
31+
slices.Sort(ends)
32+
33+
rooms := 0
34+
sPtr := 0
35+
ePtr := 0
36+
for sPtr < n {
37+
if starts[sPtr] < ends[ePtr] { // 현재 사용가능한 회의실이 없음 (현재 진행중인 모든 회의가 starts[sPtr]보다 큼)
38+
rooms++ // 새로운 회의실 추가함
39+
} else {
40+
ePtr++ // 기존 회의실 중에 남는 방이 있음, 새로운 회의실 추가하지 않음
41+
}
42+
sPtr++
43+
}
44+
45+
return rooms
46+
}

reverse-bits/flynn.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/*
2+
풀이
3+
- 원본 uint32 num에 대하여 LSB부터(가장 오른쪽 bit) 탐색합니다
4+
LSB % 2 == 1 -> uint32의 새로운 MSB에(가장 왼쪽 bit) 1 추가
5+
else -> 0 추가
6+
Big O
7+
- Time complexity: O(1)
8+
- input num에 상관 없이 32번의 반복을 고정적으로 실행합니다
9+
- Space complexity: O(1)
10+
*/
11+
12+
func reverseBits(num uint32) uint32 {
13+
var res uint32 = 0
14+
for i := 0; i < 32; i++ {
15+
// using numerical operators
16+
// if num % 2 == 1 {
17+
// res = res * 2 + 1
18+
// } else {
19+
// res *= 2
20+
// }
21+
// num /= 2
22+
23+
// using bitwise operators
24+
res = (res << 1) | (num & 1)
25+
num >>= 1
26+
}
27+
28+
return res
29+
}

word-search-ii/flynn.go

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
/*
2+
풀이
3+
- Trie 자료구조와 2차원 배열에서의 DFS & Backtracking을 사용하여 풀이할 수 있습니다
4+
Big O
5+
- M, N: 주어진 2차원 배열 board의 행, 열 크기
6+
- Max(W): 주어진 배열 words 중에서 가장 길이가 긴 단어의 길이
7+
- Sum(W): 주어진 배열 words에 포함된 모든 단어의 길이의 총합
8+
- Time complexity: O(Sum(W) + MN * Max(W))
9+
- building trie: O(Sum(W))
10+
- 각 단어의 모든 문자를 한 번씩 조회합니다
11+
- 반복문: O(MN * Max(W))
12+
- 행, 열에 대한 반복: O(MN)
13+
- dfs: O(Max(W))
14+
- 한 좌표에 대해 dfs 함수를 trie의 최대 깊이, 즉 O(Max(W))만큼 호출합니다
15+
- Space complexity: O(Sum(W) + Max(W))
16+
- building trie: O(Sum(W)) at worst
17+
- dfs: O(Max(W))
18+
- 재귀 호출 스택의 깊이를 고려해야 합니다
19+
*/
20+
21+
func findWords(board [][]byte, words []string) []string {
22+
// building trie
23+
root := &trieNode{}
24+
for _, w := range words {
25+
root.add(w)
26+
}
27+
28+
m := len(board)
29+
n := len(board[0])
30+
res := make([]string, 0, len(words)) // create result
31+
for r := 0; r < m; r++ {
32+
for c := 0; c < n; c++ {
33+
if len(res) == len(words) { // early break if we found all the words
34+
break
35+
}
36+
if root.children[idx(board[r][c])] != nil { // dfs if you found starting letter of any words
37+
dfs(r, c, &board, root, &res)
38+
}
39+
}
40+
}
41+
42+
return res
43+
}
44+
45+
// ----- Implementation of TrieNode -----
46+
type trieNode struct {
47+
children [26]*trieNode
48+
word string
49+
}
50+
51+
func (t *trieNode) add(w string) {
52+
for i, c := range w {
53+
if t.children[c-'a'] == nil { // create new child node if there wasn't
54+
t.children[c-'a'] = &trieNode{}
55+
}
56+
t = t.children[c-'a']
57+
if i == len(w)-1 {
58+
t.word = w
59+
}
60+
}
61+
}
62+
63+
// ----- Dfs -----
64+
func dfs(r, c int, board *[][]byte, parentNode *trieNode, res *[]string) {
65+
currLetter := (*board)[r][c]
66+
currNode := parentNode.children[idx(currLetter)]
67+
// if current trie node represents some word, then append it to the result
68+
if currNode.word != "" {
69+
*res = append(*res, currNode.word)
70+
currNode.word = "" // prevent duplicate words into the result
71+
}
72+
// mark current cell as visited
73+
(*board)[r][c] = '#'
74+
// search for the 4 directions
75+
m := len(*board)
76+
n := len((*board)[0])
77+
dr := []int{0, 0, 1, -1}
78+
dc := []int{1, -1, 0, 0}
79+
for i := 0; i < 4; i++ {
80+
nr := r + dr[i]
81+
nc := c + dc[i]
82+
if !(0 <= nr && nr < m) || !(0 <= nc && nc < n) { // skip the invalid coordinates
83+
continue
84+
}
85+
if (*board)[nr][nc] == '#' { // skip the visited cell
86+
continue
87+
}
88+
if currNode.children[idx((*board)[nr][nc])] != nil {
89+
dfs(nr, nc, board, currNode, res)
90+
}
91+
}
92+
// restore the cell
93+
(*board)[r][c] = currLetter
94+
}
95+
96+
// ----- Helper -----
97+
func idx(b byte) int {
98+
return int(b - 'a')
99+
}

0 commit comments

Comments
 (0)