Skip to content

Commit 2eb5ee5

Browse files
authored
Merge pull request #1547 from hi-rachel/main
[hi-rachel] Week 10 Solutions
2 parents c05ddb4 + 1eec0e9 commit 2eb5ee5

File tree

5 files changed

+216
-0
lines changed

5 files changed

+216
-0
lines changed

course-schedule/hi-rachel.py

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
"""
2+
https://leetcode.com/problems/course-schedule/
3+
4+
문제: 수강 해야 하는 모든 강좌의 수 numCourses가 주어질 때, 모든 강좌를 끝낼 수 있으면 true, 아니면 false를 반환해라.
5+
prerequisites[i] = [ai, bi], bi를 수강하기 위해선 반드시 ai를 사전 수강해야만 한다.
6+
7+
풀이: 사이클이 있으면 수강 불가능 (순환 참조), 없으면 수강 가능
8+
각 강좌를 Node로 보고, 선행 과목 관계를 방향이 있는 간선(Edge)로 보면 -> 방향 그래프
9+
10+
BFS 풀이
11+
1. 그래프 만들기
12+
graph[a] = [b, c] 이면 a를 듣기 전에 b, c를 들어야 한다.
13+
graph[b] = [a] 이면 b를 듣기 전에 a를 들어야 한다.
14+
15+
2. 진입 차수 계산
16+
진입 차수: 어떤 노드로 들어오는 간선의 수
17+
진입 차수가 0인 노드는 바로 들을 수 있는 강의
18+
19+
3. Queue에 진입 차수가 0인 노드부터 넣고 시작
20+
Queue에서 꺼낸 노드를 기준으로, 연결된 노드들의 진입차수를 하나씩 줄인다.
21+
진입차수가 0이 된 노드는 새로 Queue에 추가
22+
23+
4, 처리된 노드 수가 전체 강의 수와 같으면 True, 아니면 False
24+
25+
TC: O(V + E), V: 과목 수, E: prerequisite 관계 수
26+
SC: O(V + E), 그래프 + 진입차수 배열
27+
"""
28+
29+
from typing import List
30+
from collections import defaultdict, deque
31+
32+
class Solution:
33+
def canFinish(self, numCourses: int, prerequisites: List[List[int]]) -> bool:
34+
graph = defaultdict(list)
35+
indegree = [0] * numCourses
36+
37+
# 1. 그래프 만들기, 2. 진입차수 계산
38+
# 수강 강의, 사전 강의
39+
for course, prereq in prerequisites:
40+
graph[prereq].append(course)
41+
indegree[course] += 1
42+
43+
# 3. Queue에 진입 차수가 0인 노드부터 넣고 시작
44+
queue = deque([i for i in range(numCourses) if indegree[i] == 0])
45+
completed = 0
46+
47+
# 4. BFS 탐색, 처리된 노드 수가 전체 강의 수와 같으면 True, 아니면 False
48+
while queue:
49+
# queue에서 꺼낸 과목을 수강 완료 처리
50+
current = queue.popleft()
51+
completed += 1
52+
53+
for neighbor in graph[current]:
54+
indegree[neighbor] -= 1
55+
if indegree[neighbor] == 0:
56+
queue.append(neighbor)
57+
58+
return completed == numCourses

invert-binary-tree/hi-rachel.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
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+
13+
TC: O(n), SC: O(n)
14+
n = 트리 내의 노드 수
15+
"""
16+
class Solution:
17+
def invertTree(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
18+
if not root:
19+
return
20+
root.left, root.right = self.invertTree(root.right), self.invertTree(root.left)
21+
return root
22+
23+
"""
24+
스택 풀이
25+
26+
TC: O(n), SC: O(n)
27+
"""
28+
class Solution:
29+
def invertTree(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
30+
stack = [root]
31+
while stack:
32+
node = stack.pop()
33+
if not node:
34+
continue
35+
node.left, node.right = node.right, node.left
36+
stack += [node.left, node.right]
37+
return root

jump-game/hi-rachel.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
"""
2+
https://leetcode.com/problems/jump-game/description/
3+
4+
문제: 배열 nums가 주어질 때, 각 인덱스에서 최대 점프 거리를 나타내는 배열이다.
5+
배열의 마지막 인덱스에 도달할 수 있으면 true, 아니면 false를 반환해라.
6+
7+
풀이:
8+
1. 현재 인덱스에서 최대 점프 거리를 계산한다.
9+
2. 최대 점프 거리가 배열의 마지막 인덱스를 넘으면 true, 아니면 false를 반환한다.
10+
11+
TC: O(n), SC: O(1)
12+
"""
13+
14+
from typing import List
15+
16+
class Solution:
17+
def canJump(self, nums: List[int]) -> bool:
18+
reach = 0 # 현재까지 도달 가능한 최대 인덱스
19+
for idx in range(len(nums)): # 각 위치 순회
20+
if idx <= reach: # 현재 인덱스가 도달 가능한 최대 인덱스 이하면
21+
reach = max(reach, idx + nums[idx]) # 최대 점프 거리 갱신
22+
return len(nums) - 1 <= reach # 마지막 인덱스가 도달 가능한 최대 인덱스 이상이면 true

merge-k-sorted-lists/hi-rachel.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
"""
2+
https://leetcode.com/problems/merge-k-sorted-lists/description/
3+
4+
문제: k개의 링크드 리스트가 주어지고, 각 링크드 리스트가 오름차순으로 정렬이 되어있다.
5+
모든 링크드 리스트를 병합하여 하나의 정렬된 링크드 리스트를 만들어라.
6+
7+
풀이:
8+
heapq를 쓰면 항상 가장 작은 값을 O(log k) 시간에 꺼낼 수 있음.
9+
heapq -> '최소 힙 구조' -> 내부적으로 항상 가장 작은 값이 루트에 오도록 정렬됨.
10+
11+
1. 각 리스트의 첫 노드를 heap에 넣음 (val, 고유번호, 노드)
12+
2. heap에서 가장 작은 값 꺼내면서 결과 리스트 구성
13+
3. 다음 노드를 힙에 추가
14+
15+
n = 모든 노드의 총 개수
16+
k = 연결 리스트의 개수
17+
18+
TC: O(n log k)
19+
- n개의 노드를 각각 힙에 1번씩 push, 1번씩 pop함 → 총 2n번 힙 연산
20+
- 각 힙 연산은 log k 시간 (힙 크기 최대 k)
21+
22+
SC: O(k)
23+
- 힙에 최대 k개의 노드가 동시에 들어감
24+
"""
25+
26+
from typing import List, Optional
27+
import heapq
28+
29+
# Definition for singly-linked list.
30+
class ListNode:
31+
def __init__(self, val=0, next=None):
32+
self.val = val
33+
self.next = next
34+
35+
36+
class Solution:
37+
def mergeKLists(self, lists: List[Optional[ListNode]]) -> Optional[ListNode]:
38+
heap = []
39+
40+
# 1. 각 리스트의 첫 노드를 heap에 넣음 (val, 고유번호, 노드)
41+
for idx, node in enumerate(lists):
42+
if node:
43+
heapq.heappush(heap, (node.val, idx, node))
44+
45+
dummy = curr = ListNode(-1)
46+
47+
# 2. heap에서 가장 작은 값 꺼내면서 결과 리스트 구성
48+
while heap:
49+
val, idx, node = heapq.heappop(heap) # 가장 작은 노드 꺼내기
50+
curr.next = node # 결과 리스트에 붙이기
51+
curr = curr.next # 다음 노드로 이동
52+
53+
if node.next:
54+
# 다음 노드를 힙에 추가
55+
heapq.heappush(heap, (node.next.val, idx, node.next))
56+
57+
return dummy.next
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
"""
2+
https://leetcode.com/problems/search-in-rotated-sorted-array/solutions/
3+
4+
문제: 회전된 오름차순 정렬된 배열 nums에서 target 값의 인덱스를 반환하라.
5+
6+
Idea: 이진 탐색 패턴 사용
7+
8+
TC: O(logN)
9+
SC: O(1)
10+
"""
11+
12+
from typing import List
13+
14+
class Solution:
15+
def search(self, nums: List[int], target: int) -> int:
16+
left, right = 0, len(nums) - 1
17+
18+
while left <= right:
19+
mid = (left + right) // 2
20+
21+
if nums[mid] == target:
22+
return mid
23+
24+
# 왼쪽이 정렬된 경우
25+
if nums[left] <= nums[mid]:
26+
# target이 정해진 구간에 있는 경우
27+
if nums[left] <= target < nums[mid]:
28+
# 왼쪽만 탐색하도록 right를 줄임
29+
right = mid - 1
30+
# 아니라면 오른쪽으로 범위를 옮김
31+
else:
32+
left = mid + 1
33+
# 오른쪽이 정렬된 경우
34+
else:
35+
# target이 정해진 구간에 있는 경우
36+
if nums[mid] < target <= nums[right]:
37+
# 오른쪽만 탐색하도록 left를 늘림
38+
left = mid + 1
39+
# 아니라면 왼쪽으로 범위를 옮김
40+
else:
41+
right = mid - 1
42+
return -1

0 commit comments

Comments
 (0)