Skip to content

Commit d53cb23

Browse files
authored
Merge pull request #1600 from hi-rachel/main
[hi-rachel] WEEK 12 solutions
2 parents d61045d + f7a9d09 commit d53cb23

File tree

4 files changed

+192
-0
lines changed

4 files changed

+192
-0
lines changed
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
"""
2+
구간이 겹쳐 삭제해야 되는 최소 구간의 수를 반환해라
3+
-> Greedy
4+
-> '겹치지 않게 최대한 많은 구간을 남기고, 나머지를 제거'
5+
6+
문제 풀이
7+
1. 끝나는 시간 기준으로 오름차순 정렬
8+
2. 이전 구간의 끝과 현재 구간의 시작을 비교
9+
3. 겹치면 현재 구간을 제거
10+
11+
TC: O(n log n), 정렬 O(n log n) + 모든 interval 한 번씩 순회 O(n)
12+
SC: O(1)
13+
"""
14+
15+
from typing import List
16+
17+
class Solution:
18+
def eraseOverlapIntervals(self, intervals: List[List[int]]) -> int:
19+
# 끝나는 시간이 빠른 순으로 정렬
20+
# -> 일찍 끝나는 구간을 선택하면, 이후에 더 많은 구간을 넣을 수 있는 여지가 커짐!
21+
intervals.sort(key=lambda x: x[1])
22+
23+
# 첫 구간 선택
24+
prev_end = float('-inf') # 음의 무한대로 비교의 기준값 가장 작게 설정 -> 첫 번째 구간 무조건 선택됨
25+
count = 0
26+
27+
# 하나씩 검사
28+
for start, end in intervals:
29+
if start >= prev_end:
30+
# 겹치지 않음 -> 그대로 유지
31+
prev_end = end
32+
else:
33+
# 겹침 -> 하나 제거
34+
count += 1
35+
36+
return count
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/**
2+
* TC: O(N + E), N: 노드의 개수, E: 간선의 개수
3+
* SC: O(N + E)
4+
*/
5+
6+
// DFS
7+
function countComponentsDFS(n: number, edges: number[][]): number {
8+
const graph: number[][] = Array.from({ length: n }, () => []);
9+
10+
// 그래프 초기화
11+
for (const [u, v] of edges) {
12+
graph[u].push(v);
13+
graph[v].push(u);
14+
}
15+
16+
const visited = new Set<number>();
17+
18+
function dfs(node: number) {
19+
visited.add(node);
20+
for (const neighbor of graph[node]) {
21+
if (!visited.has(neighbor)) {
22+
dfs(neighbor);
23+
}
24+
}
25+
}
26+
27+
let components = 0;
28+
for (let i = 0; i < n; i++) {
29+
if (!visited.has(i)) {
30+
components++;
31+
dfs(i);
32+
}
33+
}
34+
35+
return components;
36+
}
37+
38+
// BFS
39+
function countComponentsBFS(n: number, edges: number[][]): number {
40+
const graph: number[][] = Array.from({ length: n }, () => []);
41+
42+
// 그래프 초기화
43+
for (const [u, v] of edges) {
44+
graph[u].push(v);
45+
graph[v].push(u);
46+
}
47+
48+
const visited = new Set<number>();
49+
let components = 0;
50+
51+
for (let i = 0; i < n; i++) {
52+
if (!visited.has(i)) {
53+
components++;
54+
const queue: number[] = [i];
55+
56+
while (queue.length > 0) {
57+
const node = queue.shift();
58+
if (node === undefined) continue;
59+
if (visited.has(node)) continue;
60+
visited.add(node);
61+
62+
for (const neighbor of graph[node]) {
63+
if (!visited.has(neighbor)) queue.push(neighbor);
64+
}
65+
}
66+
}
67+
}
68+
69+
return components;
70+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
"""
2+
뒤에서 n번째 노드를 없애고, linked list head를 반환해라
3+
TC: O(N), 리스트 한 번 순회
4+
SC: O(1), 포인터 2개만 사용
5+
"""
6+
7+
from typing import Optional
8+
9+
# Definition for singly-linked list.
10+
class ListNode:
11+
def __init__(self, val=0, next=None):
12+
self.val = val
13+
self.next = next
14+
15+
16+
class Solution:
17+
def removeNthFromEnd(self, head: Optional[ListNode], n: int) -> Optional[ListNode]:
18+
# dummy node를 head 앞에 두어 edge case(head 삭제 등) 처리
19+
dummy = ListNode(0, head)
20+
first = dummy
21+
second = dummy
22+
23+
# first를 n+1칸 먼저 이동 -> 두 포인터 사이 간격이 n
24+
for _ in range(n + 1):
25+
first = first.next
26+
27+
# first가 끝에 도달할 때까지 두 포인터 함께 전진
28+
while first:
29+
first = first.next
30+
second = second.next
31+
32+
# second의 다음 노드가 삭제 대상이므로 연결 건너뛰기
33+
second.next = second.next.next
34+
35+
# 실제 head는 dummy.next에 있음
36+
return dummy.next

same-tree/hi-rachel.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
from typing import Optional
2+
3+
# Definition for a binary tree node.
4+
class TreeNode:
5+
def __init__(self, val=0, left=None, right=None):
6+
self.val = val
7+
self.left = left
8+
self.right = right
9+
10+
"""
11+
재귀 풀아
12+
TC: O(N), 양 트리의 각 노드를 상대로 재귀함수를 딱 1번씩만 호출하기 때문
13+
SC: O(N), 공간복잡도 = 콜스택의 최대 높이(노드의 수)
14+
"""
15+
class Solution:
16+
def isSameTree(self, p: Optional[TreeNode], q: Optional[TreeNode]) -> bool:
17+
# 둘 다 null이면 True 반환
18+
if not p and not q:
19+
return True
20+
# 둘 중 하나면 null이면 False 반환
21+
if not p or not q:
22+
return False
23+
# val이 서로 다르면 탐색 중단, False 반환
24+
if p.val != q.val:
25+
return False
26+
# 현재 node의 val이 같다면, 좌우측 자식 트리도 같은지 확인 -> 재귀 호출
27+
return self.isSameTree(p.left, q.left) and self.isSameTree(p.right, q.right)
28+
29+
30+
"""
31+
스택 풀이
32+
TC: O(N)
33+
SC: O(N)
34+
"""
35+
36+
class Solution:
37+
def isSameTree(self, p: Optional[TreeNode], q: Optional[TreeNode]) -> bool:
38+
stack = [(p, q)]
39+
40+
while stack:
41+
p, q = stack.pop()
42+
if not p and not q:
43+
continue
44+
if not p or not q:
45+
return False
46+
if p.val != q.val:
47+
return False
48+
stack.append((p.left, q.left))
49+
stack.append((p.right, q.right))
50+
return True

0 commit comments

Comments
 (0)