-
-
Notifications
You must be signed in to change notification settings - Fork 361
[alphaorderly] WEEK 10 Solutions #2834
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
|
|
||
| """ | ||
| 시간복잡도: O(n + m) | ||
| 공간복잡도: O(n + m) | ||
|
|
||
| - 각 과목의 진입 차수(in_degree)를 계산한다. | ||
| - 각 과목의 인접 리스트(graph)를 구성한다. | ||
| - 진입 차수가 0인 과목을 큐에 추가한다. | ||
| - 큐에서 과목을 하나씩 꺼내고, 그 과목을 선수과목으로 가지는 모든 과목의 진입 차수를 1씩 감소시킨다. | ||
| - 진입 차수가 0이 된 과목을 큐에 추가한다. | ||
| - 큐를 모두 처리한 후, 방문한 과목의 수가 전체 과목 수와 같은지 확인한다. | ||
| """ | ||
| class Solution: | ||
| def canFinish(self, numCourses: int, prerequisites: List[List[int]]) -> bool: | ||
| in_degree = [0] * numCourses | ||
| graph = defaultdict(list) | ||
| entered_courses = 0 | ||
|
|
||
| for s, e in prerequisites: | ||
| in_degree[s] += 1 | ||
| graph[e].append(s) | ||
|
|
||
| queue = deque([]) | ||
|
|
||
| for course, count in enumerate(in_degree): | ||
| if count == 0: | ||
| queue.append(course) | ||
| entered_courses += 1 | ||
|
|
||
| while queue: | ||
| course = queue.popleft() | ||
|
|
||
| for next_course in graph[course]: | ||
| in_degree[next_course] -= 1 | ||
| if in_degree[next_course] == 0: | ||
| entered_courses += 1 | ||
| queue.append(next_course) | ||
|
|
||
| return entered_courses == numCourses |
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🏷️ 알고리즘 패턴 분석invert-binary-tree/alphaorderly.py# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
"""
시간복잡도: O(n)
공간복잡도: O(h) - 트리의 높이(h)만큼 재귀 호출이 쌓인다.
- 루트 노드부터 시작해, 왼쪽과 오른쪽 자식을 각각 재귀적으로 반전한다.
- 재귀 함수는 현재 노드가 None이면 바로 None을 반환한다.
- 왼쪽과 오른쪽 자식을 반전한 결과를 각각 root.right, root.left로 할당하여 두 자식을 서로 바꾼다.
- 최종적으로 반전된 루트 노드를 반환한다.
"""
class Solution:
def invertTree(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
if not root:
return None
root.left, root.right = self.invertTree(root.right), self.invertTree(root.left)
return root
📊 시간/공간 복잡도 분석
풀이 1:
|
| 복잡도 | |
|---|---|
| Time | O(n) |
| Space | O(h) |
피드백: 트리의 모든 노드를 한 번씩 방문하여 자식 노드를 스왑한다.
개선 제안: 현재 구현이 적절해 보입니다.
풀이 2: Solution.invertTree — Time: O(n) / Space: O(h)
| 복잡도 | |
|---|---|
| Time | O(n) |
| Space | O(h) |
피드백: 재귀 깊이가 트리의 높이에 비례한다.
개선 제안: 현재 구현이 적절해 보입니다.
💡 풀이에 시간/공간 복잡도를 주석으로 남겨보세요!
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| # Definition for a binary tree node. | ||
| # class TreeNode: | ||
| # def __init__(self, val=0, left=None, right=None): | ||
| # self.val = val | ||
| # self.left = left | ||
| # self.right = right | ||
|
|
||
| """ | ||
| 시간복잡도: O(n) | ||
| 공간복잡도: O(h) - 트리의 높이(h)만큼 재귀 호출이 쌓인다. | ||
|
|
||
| - 루트 노드부터 시작해, 왼쪽과 오른쪽 자식을 각각 재귀적으로 반전한다. | ||
| - 재귀 함수는 현재 노드가 None이면 바로 None을 반환한다. | ||
| - 왼쪽과 오른쪽 자식을 반전한 결과를 각각 root.right, root.left로 할당하여 두 자식을 서로 바꾼다. | ||
| - 최종적으로 반전된 루트 노드를 반환한다. | ||
| """ | ||
| class Solution: | ||
| def invertTree(self, root: Optional[TreeNode]) -> Optional[TreeNode]: | ||
| if not root: | ||
| return None | ||
|
|
||
| root.left, root.right = self.invertTree(root.right), self.invertTree(root.left) | ||
| return root |
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🏷️ 알고리즘 패턴 분석jump-game/alphaorderly.py"""
시간복잡도: O(n)
공간복잡도: O(1)
- 현재 위치(index)에서 갈 수 있는 가장 먼 위치(furthest)를 갱신한다.
- furthest가 현재 위치보다 작으면 도달할 수 없으므로 False를 반환한다.
- 갱신된 furthest가 마지막 인덱스 이상이 되면 True를 반환한다.
"""
class Solution:
def canJump(self, nums: List[int]) -> bool:
N = len(nums)
furthest = 0
for index, jump in enumerate(nums):
if furthest < index:
return False
furthest = max(furthest, index + jump)
if furthest >= N - 1:
return True
return False
📊 시간/공간 복잡도 분석
피드백: 그리디 방식으로 최댓값을 갱신하며 도달 가능성을 판단한다. 개선 제안: 현재 구현이 적절해 보입니다.
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| """ | ||
| 시간복잡도: O(n) | ||
| 공간복잡도: O(1) | ||
|
|
||
| - 현재 위치(index)에서 갈 수 있는 가장 먼 위치(furthest)를 갱신한다. | ||
| - furthest가 현재 위치보다 작으면 도달할 수 없으므로 False를 반환한다. | ||
| - 갱신된 furthest가 마지막 인덱스 이상이 되면 True를 반환한다. | ||
| """ | ||
| class Solution: | ||
| def canJump(self, nums: List[int]) -> bool: | ||
| N = len(nums) | ||
| furthest = 0 | ||
|
|
||
| for index, jump in enumerate(nums): | ||
| if furthest < index: | ||
| return False | ||
|
|
||
| furthest = max(furthest, index + jump) | ||
| if furthest >= N - 1: | ||
| return True | ||
|
|
||
| return False |
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🏷️ 알고리즘 패턴 분석merge-k-sorted-lists/alphaorderly.py"""
시간복잡도: O(n log k)
공간복잡도: O(k)
- k는 연결 리스트의 개수, n은 모든 노드의 개수
- 각 연결 리스트의 첫 번째 노드 값을 (값, 인덱스) 형태로 힙에 추가한다.
- 힙에서 가장 작은 값을 꺼내 결과 더미 연결 리스트에 노드로 연결한다.
- 꺼낸 노드가 속했던 리스트의 다음 노드가 있으면 힙에 추가한다.
- 힙이 빌 때까지 위 과정을 반복한다.
- 더미 연결 리스트의 다음 노드를 반환한다.
"""
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def mergeKLists(self, lists: List[Optional[ListNode]]) -> Optional[ListNode]:
ans = ListNode()
head = ans
values = [(node.val, index) for index, node in enumerate(lists) if node]
heapify(values)
while values:
_, index = heappop(values)
head.next = lists[index]
head = head.next
lists[index] = lists[index].next
if lists[index]:
heappush(values, (lists[index].val, index))
return ans.next
📊 시간/공간 복잡도 분석
피드백: 힙에 각 리스트의 현재 노드를 담고, 하나씩 꺼내며 연결리스트를 구성한다. 개선 제안: 현재 구현이 적절해 보입니다.
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| """ | ||
| 시간복잡도: O(n log k) | ||
| 공간복잡도: O(k) | ||
| - k는 연결 리스트의 개수, n은 모든 노드의 개수 | ||
|
|
||
| - 각 연결 리스트의 첫 번째 노드 값을 (값, 인덱스) 형태로 힙에 추가한다. | ||
| - 힙에서 가장 작은 값을 꺼내 결과 더미 연결 리스트에 노드로 연결한다. | ||
| - 꺼낸 노드가 속했던 리스트의 다음 노드가 있으면 힙에 추가한다. | ||
| - 힙이 빌 때까지 위 과정을 반복한다. | ||
| - 더미 연결 리스트의 다음 노드를 반환한다. | ||
| """ | ||
| # Definition for singly-linked list. | ||
| # class ListNode: | ||
| # def __init__(self, val=0, next=None): | ||
| # self.val = val | ||
| # self.next = next | ||
| class Solution: | ||
| def mergeKLists(self, lists: List[Optional[ListNode]]) -> Optional[ListNode]: | ||
| ans = ListNode() | ||
| head = ans | ||
|
|
||
| values = [(node.val, index) for index, node in enumerate(lists) if node] | ||
| heapify(values) | ||
|
|
||
| while values: | ||
| _, index = heappop(values) | ||
|
|
||
| head.next = lists[index] | ||
| head = head.next | ||
|
|
||
| lists[index] = lists[index].next | ||
| if lists[index]: | ||
| heappush(values, (lists[index].val, index)) | ||
|
|
||
| return ans.next |
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🏷️ 알고리즘 패턴 분석search-in-rotated-sorted-array/alphaorderly.py"""
시간복잡도: O(log n)
공간복잡도: O(1)
- 회전된 정렬 배열에서 이진 탐색으로 target을 찾는다.
- mid와 target이 원래 배열의 왼쪽 절반에 있었는지, 오른쪽 절반에 있었는지를 구분한다.
- 기준: nums[mid] > nums[N-1] 이면 mid가 왼쪽(회전되기 전 더 작은 쪽), 아니면 오른쪽.
- target도 같은 기준으로 왼쪽/오른쪽인지 판별.
- mid와 target이 서로 다른 쪽에 있으면, target이 있는 쪽으로 포인터를 이동 (left 또는 right 값을 조정).
- mid == target 이면 mid 반환.
- 찾지 못하면 -1 반환.
"""
class Solution:
def search(self, nums: List[int], target: int) -> int:
N = len(nums)
left = 0
right = N - 1
while left <= right:
mid = (left + right) // 2
if target == nums[mid]:
return mid
mid_left = nums[mid] > nums[N - 1]
target_left = target > nums[N - 1]
if nums[mid] > target:
if mid_left != target_left:
left = mid + 1
else:
right = mid - 1
elif mid_left != target_left:
right = mid - 1
else:
left = mid + 1
return -1
📊 시간/공간 복잡도 분석
피드백: 중간 값의 위치에 따라 왼쪽/오른쪽 반쪽을 판단해 탐색 범위를 축소한다. 개선 제안: 현재 구현이 적절해 보입니다.
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| """ | ||
| 시간복잡도: O(log n) | ||
| 공간복잡도: O(1) | ||
|
|
||
| - 회전된 정렬 배열에서 이진 탐색으로 target을 찾는다. | ||
| - mid와 target이 원래 배열의 왼쪽 절반에 있었는지, 오른쪽 절반에 있었는지를 구분한다. | ||
| - 기준: nums[mid] > nums[N-1] 이면 mid가 왼쪽(회전되기 전 더 작은 쪽), 아니면 오른쪽. | ||
| - target도 같은 기준으로 왼쪽/오른쪽인지 판별. | ||
| - mid와 target이 서로 다른 쪽에 있으면, target이 있는 쪽으로 포인터를 이동 (left 또는 right 값을 조정). | ||
| - mid == target 이면 mid 반환. | ||
| - 찾지 못하면 -1 반환. | ||
| """ | ||
| class Solution: | ||
| def search(self, nums: List[int], target: int) -> int: | ||
| N = len(nums) | ||
| left = 0 | ||
| right = N - 1 | ||
|
|
||
| while left <= right: | ||
| mid = (left + right) // 2 | ||
|
|
||
| if target == nums[mid]: | ||
| return mid | ||
|
|
||
| mid_left = nums[mid] > nums[N - 1] | ||
| target_left = target > nums[N - 1] | ||
|
|
||
| if nums[mid] > target: | ||
| if mid_left != target_left: | ||
| left = mid + 1 | ||
| else: | ||
| right = mid - 1 | ||
| elif mid_left != target_left: | ||
| right = mid - 1 | ||
| else: | ||
| left = mid + 1 | ||
|
|
||
| return -1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🏷️ 알고리즘 패턴 분석
course-schedule/alphaorderly.py
📊 시간/공간 복잡도 분석
풀이 1:
Solution.canFinish— Time: O(n + m) / Space: O(n + m)피드백: 그래프 인접 리스트와 진입 차수를 이용해 사이클 여부를 판단하는 표준 풀이이다.
개선 제안: 현재 구현이 적절해 보입니다.
풀이 2:
Solution.canFinish— Time: O(n + m) / Space: O(n + m)피드백: 임의의 추가 제약 없이도 동작하는 위상 정렬 풀이이다.
개선 제안: 현재 구현이 적절해 보입니다.