Skip to content

Commit e0819e1

Browse files
authored
Merge branch 'DaleStudy:main' into main
2 parents 1d41918 + 95bed90 commit e0819e1

36 files changed

+1189
-2
lines changed
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
"""
2+
Constraints:
3+
- -10^5 <= num <= 10^5
4+
- There will be at least one element in the data structure before calling findMedian.
5+
- At most 5 * 10^4 calls will be made to addNum and findMedian.
6+
7+
Time Complexity:
8+
- addNum(): O(nlogn)
9+
- 매번 정렬하기 때문
10+
- findMedian(): O(1)
11+
- 정렬된 리스트에서 인덱스 접근
12+
13+
Space Complexity: O(n)
14+
- 입력된 모든 숫자를 리스트에 저장
15+
16+
풀이방법:
17+
1. 리스트 자료구조 사용
18+
2. 리스트에 각 요소들 추가 후 정렬
19+
3. 리스트의 요소 갯수가 홀수/짝수일 때의 경우를 나눠서 median 값을 구함
20+
21+
메모:
22+
- heap이 익숙하지 않아서 일단 리스트로 문제를 풀었습니다.
23+
- 나중에 heap으로 다시 풀기
24+
"""
25+
class MedianFinder:
26+
27+
def __init__(self):
28+
self.nums = []
29+
30+
def addNum(self, num: int) -> None:
31+
self.nums.append(num)
32+
self.nums.sort()
33+
34+
35+
def findMedian(self) -> float:
36+
n = len(self.nums)
37+
if n % 2 == 1:
38+
return self.nums[n // 2]
39+
else:
40+
mid1 = self.nums[n // 2 - 1]
41+
mid2 = self.nums[n // 2]
42+
return (mid1 + mid2) / 2.0
43+
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
class MedianFinder {
2+
priority_queue<int> maxHeap;
3+
priority_queue<int, vector<int>, greater<int>> minHeap;
4+
public:
5+
MedianFinder() {
6+
}
7+
8+
void addNum(int num) {
9+
if(maxHeap.empty() || num <= maxHeap.top())
10+
maxHeap.push(num);
11+
else
12+
minHeap.push(num);
13+
14+
if(maxHeap.size() > minHeap.size() + 1){
15+
minHeap.push(maxHeap.top());
16+
maxHeap.pop();
17+
}else if(maxHeap.size() < minHeap.size()){
18+
maxHeap.push(minHeap.top());
19+
minHeap.pop();
20+
}
21+
}
22+
23+
double findMedian() {
24+
if(maxHeap.size() > minHeap.size())
25+
return maxHeap.top();
26+
else if(maxHeap.size() < minHeap.size())
27+
return minHeap.top();
28+
else
29+
return (maxHeap.top() + minHeap.top()) / 2.0;
30+
}
31+
};
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*
2+
minHeap이 항상 maxHeap보다 크거나 같도록 유지한다.
3+
addNum()
4+
- maxHeap에 새로 들어온 num을 포함한 최댓값을 minHeap으로 옮긴다
5+
- 처음엔 maxHeap과 minHeap의 크기 차이가 1이므로 if문에 들어가지 않지만
6+
- 이후 num이 minHeap으로 하나 더 넘어가게 되면 maxHeap과 minHeap의 크기 차이가 2가 되므로
7+
if문에 들어가서 maxHeap쪽으로 minHeap의 최솟값을 옮긴다
8+
힙 삽입에 O(logn)이 걸리므로 시간복잡도는 O(logn)이다
9+
findMedian()
10+
- 두 힙의 top만 참조하면 되므로 시간 복잡도는 O(1)이다
11+
최소힙과 최대힙은 각각 전체 수의 절반씩을 저장한다.
12+
공간 복잡도는 O(n)이다
13+
*/
14+
class MedianFinder {
15+
public:
16+
priority_queue<int> maxHeap;
17+
priority_queue<int, vector<int>, greater<int>> minHeap;
18+
19+
MedianFinder() {
20+
}
21+
22+
void addNum(int num) {
23+
maxHeap.push(num);
24+
25+
minHeap.push(maxHeap.top());
26+
maxHeap.pop();
27+
28+
if (maxHeap.size() + 1 < minHeap.size()) {
29+
maxHeap.push(minHeap.top());
30+
minHeap.pop();
31+
}
32+
}
33+
34+
double findMedian() {
35+
if (maxHeap.size() == minHeap.size())
36+
return (minHeap.top() + maxHeap.top()) / 2.0;
37+
return minHeap.top();
38+
}
39+
};
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
class MedianFinder {
2+
arr: number[]
3+
constructor() {
4+
this.arr = []
5+
}
6+
/*
7+
Time Complexity: O(logn)
8+
Space Complexity: O(n)
9+
*/
10+
addNum(num: number): void {
11+
let left = 0
12+
let right = this.arr.length
13+
14+
while (left < right) {
15+
const mid = Math.floor((left + right) / 2)
16+
if (this.arr[mid] < num) {
17+
left = mid + 1
18+
} else {
19+
right = mid
20+
}
21+
}
22+
this.arr.splice(left, 0, num)
23+
}
24+
/*
25+
Time Complexity: O(1)
26+
Space Complexity: O(n)
27+
*/
28+
findMedian(): number {
29+
const n = this.arr.length
30+
if (n % 2 === 0) {
31+
return (this.arr[n / 2 - 1] + this.arr[n / 2]) / 2
32+
} else {
33+
return (this.arr[Math.floor(n / 2)])
34+
}
35+
}
36+
}
37+
38+
/**
39+
* Your MedianFinder object will be instantiated and called as such:
40+
* var obj = new MedianFinder()
41+
* obj.addNum(num)
42+
* var param_2 = obj.findMedian()
43+
*/
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
class Heap {
2+
constructor(compare) {
3+
this.data = [];
4+
this.compare = compare;
5+
}
6+
7+
size() {
8+
return this.data.length;
9+
}
10+
11+
peek() {
12+
return this.data[0];
13+
}
14+
15+
push(val) {
16+
this.data.push(val);
17+
this._siftUp();
18+
}
19+
20+
pop() {
21+
const top = this.peek();
22+
const bottom = this.data.pop();
23+
if (this.data.length > 0) {
24+
this.data[0] = bottom;
25+
this._siftDown();
26+
}
27+
return top;
28+
}
29+
30+
_siftUp() {
31+
let i = this.data.length - 1;
32+
const node = this.data[i];
33+
while (i > 0) {
34+
const parent = Math.floor((i - 1) / 2);
35+
if (this.compare(node, this.data[parent])) {
36+
this.data[i] = this.data[parent];
37+
i = parent;
38+
} else break;
39+
}
40+
this.data[i] = node;
41+
}
42+
43+
_siftDown() {
44+
let i = 0;
45+
const node = this.data[0];
46+
const length = this.data.length;
47+
48+
while (true) {
49+
let left = 2 * i + 1;
50+
let right = 2 * i + 2;
51+
let swap = i;
52+
53+
if (left < length && this.compare(this.data[left], this.data[swap])) {
54+
swap = left;
55+
}
56+
if (right < length && this.compare(this.data[right], this.data[swap])) {
57+
swap = right;
58+
}
59+
if (swap === i) break;
60+
61+
this.data[i] = this.data[swap];
62+
i = swap;
63+
}
64+
65+
this.data[i] = node;
66+
}
67+
}
68+
69+
var MedianFinder = function() {
70+
this.small = new Heap((a, b) => a > b); // max heap
71+
this.large = new Heap((a, b) => a < b); // min heap
72+
};
73+
74+
MedianFinder.prototype.addNum = function(num) {
75+
this.small.push(num);
76+
77+
if (
78+
this.small.size() > 0 &&
79+
this.large.size() > 0 &&
80+
this.small.peek() > this.large.peek()
81+
) {
82+
this.large.push(this.small.pop());
83+
}
84+
85+
if (this.small.size() > this.large.size() + 1) {
86+
this.large.push(this.small.pop());
87+
}
88+
if (this.large.size() > this.small.size() + 1) {
89+
this.small.push(this.large.pop());
90+
}
91+
};
92+
93+
MedianFinder.prototype.findMedian = function() {
94+
if (this.small.size() > this.large.size()) {
95+
return this.small.peek();
96+
}
97+
if (this.large.size() > this.small.size()) {
98+
return this.large.peek();
99+
}
100+
return (this.small.peek() + this.large.peek()) / 2;
101+
};
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/**
2+
* <a href="https://leetcode.com/problems/find-median-from-data-stream/">week13-4. find-median-from-data-stream</a>
3+
* <li>Description: Implement the MedianFinder class</li>
4+
* <li>Topics: Two Pointers, Design, Sorting, Heap (Priority Queue), Data Stream</li>
5+
* <li>Time Complexity: O(logN), Runtime 99ms </li>
6+
* <li>Space Complexity: O(N), Memory 63.68MB </li>
7+
*/
8+
9+
class MedianFinder {
10+
PriorityQueue<Integer> head;
11+
PriorityQueue<Integer> tail;
12+
13+
public MedianFinder() {
14+
head = new PriorityQueue<>(Comparator.reverseOrder());
15+
tail = new PriorityQueue<>();
16+
}
17+
18+
public void addNum(int num) {
19+
if(head.isEmpty() || num <= head.peek()) {
20+
head.add(num);
21+
} else {
22+
tail.add(num);
23+
}
24+
25+
if (head.size() > tail.size() + 1) {
26+
tail.add(head.poll());
27+
} else if (head.size() < tail.size()) {
28+
head.add(tail.poll());
29+
}
30+
}
31+
32+
public double findMedian() {
33+
if(head.size() == tail.size()){
34+
return ((double)head.peek() + tail.peek()) / 2;
35+
}
36+
return head.peek();
37+
}
38+
}
39+
40+
/**
41+
* Your MedianFinder object will be instantiated and called as such:
42+
* MedianFinder obj = new MedianFinder();
43+
* obj.addNum(num);
44+
* double param_2 = obj.findMedian();
45+
*/
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
"""
2+
[문제풀이]
3+
# Inputs
4+
5+
# Outputs
6+
7+
# Constraints
8+
9+
# Ideas
10+
11+
[회고]
12+
13+
"""
14+
15+
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/*
2+
풀이 :
3+
maxHeap과 minHeap 사용
4+
5+
heap에 담긴 총 수 : N
6+
7+
addNum()
8+
작은 수 집합은 maxHeap, 큰 수 집합은 minHeap에 담는다
9+
minHeap과 maxHeap의 개수차이를 1로 유지하면서 addNum
10+
11+
TC : O (log N)
12+
힙에 넣고 뺄 때 O (logN) 의 시간 소요
13+
14+
SC : O (N)
15+
총 힙 크기는 N에 비례
16+
17+
findMedian()
18+
더 크게 유지되는 것은 minHeap이므로 둘 의 개수가 같지 않을경우(총 홀수개) minHeap.top() 리턴
19+
같을 경우 총개수가 짝수개이므로 두 힙.top()의 평균을 리턴
20+
21+
TC : O (1)
22+
각 힙에서 root값 확인은 O(1)의 시간 소요
23+
SC : O (1)
24+
*/
25+
26+
#include <queue>
27+
#include <vector>
28+
using namespace std;
29+
30+
class MedianFinder {
31+
public:
32+
priority_queue<int> maxHeap;
33+
priority_queue<int, vector<int>, greater<int>> minHeap;
34+
35+
MedianFinder() {
36+
37+
}
38+
39+
void addNum(int num) {
40+
if (minHeap.empty() || num >= minHeap.top())
41+
minHeap.push(num);
42+
else
43+
maxHeap.push(num);
44+
45+
if (minHeap.size() > maxHeap.size() + 1) {
46+
maxHeap.push(minHeap.top());
47+
minHeap.pop();
48+
}
49+
else if (maxHeap.size() > minHeap.size()) {
50+
minHeap.push(maxHeap.top());
51+
maxHeap.pop();
52+
}
53+
}
54+
55+
double findMedian() {
56+
if (maxHeap.size() == minHeap.size())
57+
return static_cast<double>(maxHeap.top() + minHeap.top()) / 2;
58+
else
59+
return minHeap.top();
60+
}
61+
};
62+
63+
/**
64+
* Your MedianFinder object will be instantiated and called as such:
65+
* MedianFinder* obj = new MedianFinder();
66+
* obj->addNum(num);
67+
* double param_2 = obj->findMedian();
68+
*/

0 commit comments

Comments
 (0)