Skip to content

[Flynn] Week13 #576

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

Merged
merged 7 commits into from
Nov 9, 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
67 changes: 67 additions & 0 deletions find-median-from-data-stream/flynn.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
풀이
- 이진탐색을 이용합니다
Big O
- N: 현재 MedianFinder.nums의 크기
- AddNum
- Time complexity: O(N)
- bisect -> O(logN)
- slices.Insert -> O(N)
- Space complexity: O(1)
- FindMedian
- Time complexity: O(1)
- Space complexity: O(1)
*/

import "slices"

type MedianFinder struct {
nums []int
}

func Constructor() MedianFinder {
mf := MedianFinder{}
mf.nums = make([]int, 0)
return mf
}

func (this *MedianFinder) AddNum(num int) {
n := len(this.nums)
if n == 0 {
this.nums = append(this.nums, num)
} else {
idx := bisectLeft(this.nums, num)
this.nums = slices.Insert(this.nums, idx, num)
}
}

func (this *MedianFinder) FindMedian() float64 {
n := len(this.nums)
if n%2 == 0 {
return (float64(this.nums[n/2-1]) + float64(this.nums[n/2])) / 2
} else {
return float64(this.nums[n/2])
}
}

// ----- Helper -----
func bisectLeft(arr []int, x int) int {
lo := 0
hi := len(arr)
for lo < hi {
mid := lo + (hi-lo)/2
if arr[mid] < x {
lo = mid + 1
} else {
hi = mid
}
}
return lo
}

/**
* Your MedianFinder object will be instantiated and called as such:
* obj := Constructor();
* obj.AddNum(num);
* param_2 := obj.FindMedian();
*/
72 changes: 72 additions & 0 deletions house-robber/flynn.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
풀이 1
- DP를 이용하여 풀이합니다
아래 배열 두 개를 이용합니다
robbed[i]: i번째 집을 털면서 구한 rob(nums[:i+1])의 최대값
unrobbed[i]: i번째 집을 안 털면서 구한 rob(nums[:i+1])의 최대값
두 배열을 이용하여 아래와 같은 점화식을 세울 수 있습니다
robbed[i] = nums[i] + max(robbed[i-2], unrobbed[i-1])
unrobbed[i] = max(robbed[i-1], unrobbed[i-1])
Big O
- N: nums의 길이
- Time complexity: O(N)
- Space complexity: O(N)
*/

func rob(nums []int) int {
n := len(nums)

if n == 1 {
return nums[0]
}

robbed := make([]int, n)
robbed[0] = nums[0]
robbed[1] = nums[1]

unrobbed := make([]int, n)
unrobbed[1] = nums[0]

for i := 2; i < n; i++ {
robbed[i] = nums[i] + max(robbed[i-2], unrobbed[i-1])
unrobbed[i] = max(robbed[i-1], unrobbed[i-1])
}

return max(robbed[n-1], unrobbed[n-1])
}

/*
풀이 2
- 풀이 1과 동일한데, memoization을 위해 배열을 사용하지 않습니다
robbed[i], unrobbed[i] 계산에는 robbed[i-2], robbed[i-1], unrobbed[i-1]만 있어도 충분하기 때문입니다
Big O
- N: nums의 길이
- Time complexity: O(N)
- Space complexity: O(1)
*/

func rob(nums []int) int {
n := len(nums)

if n == 1 {
return nums[0]
}

ppRobbed := nums[0] // robbed[i-2]에 해당
pRobbed := nums[1] // robbed[i-1]에 해당
pUnrobbed := nums[0] // unrobbed[i-1]에 해당

for i := 2; i < n; i++ {
ppRobbed, pRobbed, pUnrobbed = pRobbed, nums[i]+max(ppRobbed, pUnrobbed), max(pRobbed, pUnrobbed)
}

return max(pRobbed, pUnrobbed)
}

func max(a, b int) int {
if a > b {
return a
} else {
return b
}
}
35 changes: 35 additions & 0 deletions lowest-common-ancestor-of-a-binary-search-tree/flynn.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
풀이
- common ancestor라는 조건에 맞는 node를 찾아냅니다
for common ancestor C, left subtree of C includes p (p.Val <= C.Val)
and right subtree of C includes q (C.Val <= q.Val)
이러한 조건을 만족하는 common ancestor는 BST에 하나만 존재합니다
따라서 common ancestor를 찾으면 그게 곧 lowest common ancestor입니다
Big O
- N: 노드의 개수
- H: 트리의 높이 (avg: logN, worst: N)
- Time complexity: O(H)
- Space complexity: O(H)
*/

/**
* Definition for a binary tree node.
* type TreeNode struct {
* Val int
* Left *TreeNode
* Right *TreeNode
* }
*/

func lowestCommonAncestor(root, p, q *TreeNode) *TreeNode {
if p.Val > q.Val { // p < q가 되도록 함
return lowestCommonAncestor(root, q, p)
}
if p.Val <= root.Val && root.Val <= q.Val { // common ancestor를 찾음
return root
} else if q.Val < root.Val { // left subtree 탐색
return lowestCommonAncestor(root.Left, p, q)
} else { // right subtree 탐색
return lowestCommonAncestor(root.Right, p, q)
}
}
29 changes: 29 additions & 0 deletions meeting-rooms/flynn.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
풀이
- 정렬 후 각 interval을 비교하여 풀 수 있습니다
Big O
- N: intervals의 길이
- Time complexity: O(NlogN)
- sort.Slice -> average O(NlogN)
- 두 번째 for -> O(N)
- Space complexity: O(logN)
- golang의 sort package는 pdqsort를 사용합니다 -> O(logN)
퀵소트의 재귀 호출 스택 깊이를 고려하여야 합니다
*/

import "sort"

func canAttendMeetings(intervals [][]int) bool {
sort.Slice(intervals, func(i, j int) bool {
if intervals[i][0] == intervals[j][0] {
return intervals[i][1] < intervals[j][1]
}
return intervals[i][0] < intervals[j][0]
})
for i := 0; i < len(intervals)-1; i++ {
if intervals[i][1] > intervals[i+1][0] {
return false
}
}
return true
}
39 changes: 39 additions & 0 deletions non-overlapping-intervals/flynn.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
풀이
- 나머지 interval이 overlapping하지 않도록 하기 위해 제거해야 하는 interval의 최소 개수 구하기 문제
= 서로 overlapping하지 않도록 interval을 담은 배열의 최대 길이 구하기 문제
- Activity Selection Problem이라는 유형의 문제로 치환할 수 있음 (https://en.wikipedia.org/wiki/Activity_selection_problem)
- 이 문제의 그리디 증명은 블로그에 정리해두었음 (https://blog.naver.com/sigmapi1000/223532427648?trackingCode=blog_bloghome_searchlist)
Big O
- N: intervals의 길이
- Time complexity: O(NlogN)
- sort.Slice -> O(NlogN)
- 두 번째 for문 -> O(N)
- Space complexity: O(logN)
- sort.Slice는 퀵소트의 일종을 사용하므로 재귀 호출 스택의 깊이를 고려하여야 함
*/

import "sort"

func eraseOverlapIntervals(intervals [][]int) int {
n := len(intervals)
if n == 1 {
return 0
}
sort.Slice(intervals, func(i, j int) bool { // end의 오름차순으로 정렬
return intervals[i][1] < intervals[j][1]
})
res := 0
prev := 0 // 이전 interval을 가리킴
curr := 1 // 현재 interval을 가리킴
for curr < len(intervals) {
if intervals[prev][1] > intervals[curr][0] {
res++
curr++
} else {
prev = curr
curr++
}
}
return res
}