From 30e3c301fa3fc6192225eb0b20a891a6e1c0b37f Mon Sep 17 00:00:00 2001 From: obzva Date: Mon, 4 Nov 2024 22:41:39 +0900 Subject: [PATCH 1/7] Solution 1 --- meeting-rooms/flynn.go | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 meeting-rooms/flynn.go diff --git a/meeting-rooms/flynn.go b/meeting-rooms/flynn.go new file mode 100644 index 000000000..8ef9a11a4 --- /dev/null +++ b/meeting-rooms/flynn.go @@ -0,0 +1,33 @@ +/* +풀이 +- 정렬 후 각 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 { + if len(intervals) <= 1 { + return true + } + + 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 +} From 82465850e690206e91418e6cd828c11c360ed2dc Mon Sep 17 00:00:00 2001 From: obzva Date: Mon, 4 Nov 2024 23:08:14 +0900 Subject: [PATCH 2/7] Solution 2 --- .../flynn.go | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 lowest-common-ancestor-of-a-binary-search-tree/flynn.go diff --git a/lowest-common-ancestor-of-a-binary-search-tree/flynn.go b/lowest-common-ancestor-of-a-binary-search-tree/flynn.go new file mode 100644 index 000000000..adbd3aaf0 --- /dev/null +++ b/lowest-common-ancestor-of-a-binary-search-tree/flynn.go @@ -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) + } +} From 71404ea46366a5d79eca1c05019968becbd41b81 Mon Sep 17 00:00:00 2001 From: obzva Date: Mon, 4 Nov 2024 23:33:53 +0900 Subject: [PATCH 3/7] Solution 3 --- house-robber/flynn.go | 72 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 house-robber/flynn.go diff --git a/house-robber/flynn.go b/house-robber/flynn.go new file mode 100644 index 000000000..aa2c7ba53 --- /dev/null +++ b/house-robber/flynn.go @@ -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 + } +} From 26d6fae30f9acfd9606fea6c8ba74e2d048ab990 Mon Sep 17 00:00:00 2001 From: obzva Date: Tue, 5 Nov 2024 00:04:02 +0900 Subject: [PATCH 4/7] Solution 4 --- non-overlapping-intervals/flynn.go | 39 ++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 non-overlapping-intervals/flynn.go diff --git a/non-overlapping-intervals/flynn.go b/non-overlapping-intervals/flynn.go new file mode 100644 index 000000000..a15123766 --- /dev/null +++ b/non-overlapping-intervals/flynn.go @@ -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 +} \ No newline at end of file From 08d39785842ed83899c6bf32dcee266d4c480083 Mon Sep 17 00:00:00 2001 From: obzva Date: Tue, 5 Nov 2024 00:04:44 +0900 Subject: [PATCH 5/7] lint fix --- non-overlapping-intervals/flynn.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/non-overlapping-intervals/flynn.go b/non-overlapping-intervals/flynn.go index a15123766..dbae25249 100644 --- a/non-overlapping-intervals/flynn.go +++ b/non-overlapping-intervals/flynn.go @@ -36,4 +36,4 @@ func eraseOverlapIntervals(intervals [][]int) int { } } return res -} \ No newline at end of file +} From b00d6aad98892b8eceeb05d48445582544907713 Mon Sep 17 00:00:00 2001 From: obzva Date: Tue, 5 Nov 2024 02:06:21 +0900 Subject: [PATCH 6/7] Solution 5 --- find-median-from-data-stream/flynn.go | 67 +++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 find-median-from-data-stream/flynn.go diff --git a/find-median-from-data-stream/flynn.go b/find-median-from-data-stream/flynn.go new file mode 100644 index 000000000..bc30200a9 --- /dev/null +++ b/find-median-from-data-stream/flynn.go @@ -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(); + */ From 038524d25adf4f4e34e048fab33d0368f70e0106 Mon Sep 17 00:00:00 2001 From: obzva Date: Tue, 5 Nov 2024 23:20:04 +0900 Subject: [PATCH 7/7] unnecessary shortcut logic --- meeting-rooms/flynn.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/meeting-rooms/flynn.go b/meeting-rooms/flynn.go index 8ef9a11a4..f701dae38 100644 --- a/meeting-rooms/flynn.go +++ b/meeting-rooms/flynn.go @@ -14,10 +14,6 @@ Big O import "sort" func canAttendMeetings(intervals [][]int) bool { - if len(intervals) <= 1 { - return true - } - sort.Slice(intervals, func(i, j int) bool { if intervals[i][0] == intervals[j][0] { return intervals[i][1] < intervals[j][1]