Skip to content

Commit

Permalink
Merge pull request #591 from obzva/main
Browse files Browse the repository at this point in the history
[Flynn] Week14
  • Loading branch information
obzva authored Nov 17, 2024
2 parents e6551e4 + 369dc9a commit c21e238
Show file tree
Hide file tree
Showing 5 changed files with 277 additions and 0 deletions.
52 changes: 52 additions & 0 deletions binary-tree-level-order-traversal/flynn.go
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
}
51 changes: 51 additions & 0 deletions house-robber-ii/flynn.go
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
}
}
46 changes: 46 additions & 0 deletions meeting-rooms-ii/flynn.go
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
}
29 changes: 29 additions & 0 deletions reverse-bits/flynn.go
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
}
99 changes: 99 additions & 0 deletions word-search-ii/flynn.go
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')
}

0 comments on commit c21e238

Please sign in to comment.