-
Notifications
You must be signed in to change notification settings - Fork 116
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'DaleStudy:main' into main
- Loading branch information
Showing
74 changed files
with
3,088 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,67 @@ | ||
from heapq import heappush, heappop | ||
from unittest import TestCase, main | ||
|
||
|
||
class MedianFinder: | ||
""" | ||
Runtime: 137 ms (Beats 56.16%) | ||
Time Complexity: | ||
1) addNum | ||
- 최악의 경우 heappush + (heappop + heappush) + (heappop + heapppush) 가 발생할 수 있으므로 O(5 * log n) | ||
> O(5 * log n) ~= O(log n) | ||
2) findMedian | ||
> heap의 루트 값을 가지고 사칙연산만 하므로 O(1) | ||
Memory: 39.94 MB (Beats 5.85%) | ||
Space Complexity: O(n) | ||
- max_heap은 최대 n // 2 개 혹은 n // 2 + 1개의 원소를 가지므로 O(n / 2 + 1), upper bound | ||
- min_heap은 최대 n // 2개의 원소를 가지므로 O(n / 2) | ||
> O(n / 2 + 1) + O(n / 2) ~= O(n) + O(n) ~= O(n) | ||
""" | ||
|
||
def __init__(self): | ||
self.max_heap = [] | ||
self.min_heap = [] | ||
|
||
def addNum(self, num): | ||
heappush(self.max_heap, -num) | ||
if self.min_heap and (-self.max_heap[0] > self.min_heap[0]): | ||
heappush(self.min_heap, -heappop(self.max_heap)) | ||
|
||
if len(self.max_heap) > len(self.min_heap) + 1: | ||
heappush(self.min_heap, -heappop(self.max_heap)) | ||
elif len(self.max_heap) < len(self.min_heap): | ||
heappush(self.max_heap, -heappop(self.min_heap)) | ||
|
||
def findMedian(self): | ||
if self.max_heap and self.min_heap: | ||
if len(self.max_heap) == len(self.min_heap): | ||
return ((-self.max_heap[0]) + self.min_heap[0]) / 2 | ||
else: | ||
return -self.max_heap[0] | ||
elif self.min_heap and not self.max_heap: | ||
return self.min_heap[0] | ||
elif not self.min_heap and self.max_heap: | ||
return -self.max_heap[0] | ||
else: | ||
return 0.0 | ||
|
||
|
||
class _LeetCodeTestCases(TestCase): | ||
|
||
def test_1(self): | ||
medianFinder = MedianFinder() | ||
medianFinder.addNum(-1) | ||
self.assertEqual(medianFinder.findMedian(), -1.0) | ||
medianFinder.addNum(-2) | ||
self.assertEqual(medianFinder.findMedian(), -1.5) | ||
medianFinder.addNum(-3) | ||
self.assertEqual(medianFinder.findMedian(), -2.0) | ||
medianFinder.addNum(-4) | ||
self.assertEqual(medianFinder.findMedian(), -2.5) | ||
medianFinder.addNum(-5) | ||
self.assertEqual(medianFinder.findMedian(), -3.0) | ||
|
||
|
||
if __name__ == '__main__': | ||
main() |
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,164 @@ | ||
/** | ||
* https://leetcode.com/problems/find-median-from-data-stream | ||
* array with binary search | ||
*/ | ||
class MedianFinder { | ||
// S.C. O(n) | ||
private nums: number[] = []; | ||
|
||
// T.C. O(n) | ||
addNum(num: number): void { | ||
if (this.nums.length === 0) { | ||
this.nums.push(num); | ||
return; | ||
} else { | ||
this.putNumWithBinarySearch(num); | ||
} | ||
} | ||
|
||
private putNumWithBinarySearch(num: number): void { | ||
let left = 0; | ||
let right = this.nums.length - 1; | ||
|
||
while (left <= right) { | ||
const mid = Math.floor((left + right) / 2); | ||
if (this.nums[mid] === num) { | ||
this.nums.splice(mid, 0, num); | ||
return; | ||
} else if (this.nums[mid] < num) { | ||
left = mid + 1; | ||
} else { | ||
right = mid - 1; | ||
} | ||
} | ||
|
||
// T.C. O(n) | ||
this.nums.splice(left, 0, num); | ||
} | ||
|
||
// T.C. O(1) | ||
findMedian(): number { | ||
const len = this.nums.length; | ||
|
||
if (len % 2 === 1) { | ||
return this.nums[Math.floor(len / 2)]; | ||
} else { | ||
return (this.nums[len / 2] + this.nums[len / 2 - 1]) / 2; | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* heap... | ||
* TL;DR | ||
*/ | ||
class MedianFinder { | ||
// S.C. O(n) | ||
private smallHalf: MaxHeap = new MaxHeap(); | ||
private largeHalf: MinHeap = new MinHeap(); | ||
|
||
// T.C. O(log n) | ||
addNum(num: number): void { | ||
this.smallHalf.push(num); | ||
this.largeHalf.push(this.smallHalf.pop()!); | ||
|
||
if (this.smallHalf.size() < this.largeHalf.size()) { | ||
this.smallHalf.push(this.largeHalf.pop()!); | ||
} | ||
} | ||
|
||
// T.C. O(1) | ||
findMedian(): number { | ||
if (this.smallHalf.size() === this.largeHalf.size()) { | ||
return (this.smallHalf.peek()! + this.largeHalf.peek()!) / 2; | ||
} else { | ||
return this.smallHalf.peek()!; | ||
} | ||
} | ||
} | ||
|
||
class MinHeap { | ||
protected heap: number[] = []; | ||
|
||
push(val: number): void { | ||
this.heap.push(val); | ||
this.heapifyUp(); | ||
} | ||
|
||
pop(): number | undefined { | ||
if (this.heap.length === 0) return undefined; | ||
if (this.heap.length === 1) return this.heap.pop(); | ||
|
||
const result = this.heap[0]; | ||
this.heap[0] = this.heap.pop()!; | ||
this.heapifyDown(); | ||
return result; | ||
} | ||
|
||
peek(): number | undefined { | ||
return this.heap[0]; | ||
} | ||
|
||
size(): number { | ||
return this.heap.length; | ||
} | ||
|
||
private heapifyUp(): void { | ||
let index = this.heap.length - 1; | ||
while (index > 0) { | ||
const parentIndex = Math.floor((index - 1) / 2); | ||
if (this.heap[parentIndex] <= this.heap[index]) break; | ||
|
||
this.swap(parentIndex, index); | ||
index = parentIndex; | ||
} | ||
} | ||
|
||
private heapifyDown(): void { | ||
let index = 0; | ||
while (true) { | ||
let smallest = index; | ||
const leftChild = 2 * index + 1; | ||
const rightChild = 2 * index + 2; | ||
|
||
if ( | ||
leftChild < this.heap.length && | ||
this.heap[leftChild] < this.heap[smallest] | ||
) { | ||
smallest = leftChild; | ||
} | ||
|
||
if ( | ||
rightChild < this.heap.length && | ||
this.heap[rightChild] < this.heap[smallest] | ||
) { | ||
smallest = rightChild; | ||
} | ||
|
||
if (smallest === index) break; | ||
|
||
this.swap(index, smallest); | ||
index = smallest; | ||
} | ||
} | ||
|
||
protected swap(i: number, j: number): void { | ||
[this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]]; | ||
} | ||
} | ||
|
||
class MaxHeap extends MinHeap { | ||
push(val: number): void { | ||
super.push(-val); | ||
} | ||
|
||
pop(): number | undefined { | ||
const val = super.pop(); | ||
return val === undefined ? undefined : -val; | ||
} | ||
|
||
peek(): number | undefined { | ||
const val = super.peek(); | ||
return val === undefined ? undefined : -val; | ||
} | ||
} |
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,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(); | ||
*/ |
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,42 @@ | ||
from typing import List | ||
from unittest import TestCase, main | ||
|
||
|
||
class Solution: | ||
def rob(self, nums: List[int]) -> int: | ||
return self.solve_dp(nums) | ||
|
||
""" | ||
Runtime: 0 ms (Beats 100.00%) | ||
Time Complexity: O(n) | ||
- nums 배열을 조회하며 dp 배열을 갱신하므로 O(n) | ||
- 2항에 대한 max 연산을 사용하므로 * O(2) | ||
> O(2 * n) ~= O(n) | ||
Memory: 16.62 MB (Beats 24.05%) | ||
Space Complexity: O(n) | ||
> 길이가 n인 dp 배열을 사용하므로 O(n) | ||
""" | ||
|
||
def solve_dp(self, nums: List[int]) -> int: | ||
if len(nums) <= 2: | ||
return max(nums) | ||
|
||
dp = [0] * len(nums) | ||
dp[0] = nums[0] | ||
dp[1] = max(nums[0], nums[1]) | ||
for i in range(2, len(nums)): | ||
dp[i] = max(dp[i - 1], dp[i - 2] + nums[i]) | ||
|
||
return dp[-1] | ||
|
||
|
||
class _LeetCodeTestCases(TestCase): | ||
def test_1(self): | ||
nums = [2,1,1,2] | ||
output = 4 | ||
self.assertEqual(Solution().rob(nums), output) | ||
|
||
|
||
if __name__ == '__main__': | ||
main() |
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,15 @@ | ||
/** | ||
* https://leetcode.com/problems/house-robber | ||
* T.C. O(n) | ||
* S.C. O(1) | ||
*/ | ||
function rob(nums: number[]): number { | ||
let prev = 0; | ||
let curr = 0; | ||
for (let i = 0; i < nums.length; i++) { | ||
const temp = curr; | ||
curr = Math.max(prev + nums[i], curr); | ||
prev = temp; | ||
} | ||
return curr; | ||
} |
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,21 @@ | ||
// TC: O(n) | ||
// always need to check every case | ||
// SC: O(n) | ||
// the length of the result int list is same with the length of the given nums int list | ||
class Solution { | ||
public int rob(int[] nums) { | ||
int[] result = new int[nums.length]; | ||
|
||
if (nums.length < 2) return nums[0]; | ||
if (nums.length < 3) return Math.max(nums[0], nums[1]); | ||
|
||
result[0] = nums[0]; | ||
result[1] = Math.max(nums[0], nums[1]); | ||
|
||
for (int i = 2; i < nums.length; i++) { | ||
result[i] = Math.max(result[i - 1], result[i - 2] + nums[i]); | ||
} | ||
|
||
return result[nums.length-1]; | ||
} | ||
} |
Oops, something went wrong.