Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions course-schedule/alphaorderly.py

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🏷️ 알고리즘 패턴 분석

course-schedule/alphaorderly.py
"""
시간복잡도: 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
  • 패턴: Breadth-First Search, Topological Sort, Hash Map / Hash Set
  • 설명: 그래프의 위상 정렬 방식으로 진입 차수를 이용해 순서를 해결한다. 큐를 이용한 BFS 방식으로 사이클 여부를 판단하고, 선수과목 그래프를 구성한다.

📊 시간/공간 복잡도 분석

ℹ️ 이 파일에는 2가지 풀이가 포함되어 있어 각각 분석합니다.

풀이 1: Solution.canFinish — Time: O(n + m) / Space: O(n + m)
복잡도
Time O(n + m)
Space O(n + m)

피드백: 그래프 인접 리스트와 진입 차수를 이용해 사이클 여부를 판단하는 표준 풀이이다.

개선 제안: 현재 구현이 적절해 보입니다.

풀이 2: Solution.canFinish — Time: O(n + m) / Space: O(n + m)
복잡도
Time O(n + m)
Space O(n + m)

피드백: 임의의 추가 제약 없이도 동작하는 위상 정렬 풀이이다.

개선 제안: 현재 구현이 적절해 보입니다.

💡 풀이에 시간/공간 복잡도를 주석으로 남겨보세요!

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
23 changes: 23 additions & 0 deletions invert-binary-tree/alphaorderly.py

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The 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
  • 패턴: Depth-First Search, Recursive, Binary Tree
  • 설명: 코드는 재귀적으로 트리의 자식을 방문하며 각 노드의 왼쪽/오른쪽을 서로 반전시키는 DFS 성격의 재귀 패턴으로 구현되었다. 트리 구조를 탐색하며 부분 문제를 해결해 전체 트리를 반전한다.

📊 시간/공간 복잡도 분석

ℹ️ 이 파일에는 2가지 풀이가 포함되어 있어 각각 분석합니다.

풀이 1: Solution.invertTree — Time: O(n) / Space: O(h)
복잡도
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
22 changes: 22 additions & 0 deletions jump-game/alphaorderly.py

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The 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
  • 패턴: Greedy, Binary Search
  • 설명: 코드는 현재 위치에서 도달 가능한 최대 인덱스를 갱신하며, furthest가 현재 인덱스보다 작아지면 도달 불가능을 결정한다. 이는 남은 요소들 중 최적의 경로를 빠르게 판단하는 그리디 접근으로 풀이되며, 최종적으로 마지막 인덱스에 도달하는지 확인한다.

📊 시간/공간 복잡도 분석

복잡도
Time O(n)
Space O(1)

피드백: 그리디 방식으로 최댓값을 갱신하며 도달 가능성을 판단한다.

개선 제안: 현재 구현이 적절해 보입니다.

💡 풀이에 시간/공간 복잡도를 주석으로 남겨보세요!

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
35 changes: 35 additions & 0 deletions merge-k-sorted-lists/alphaorderly.py

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The 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
  • 패턴: Heap / Priority Queue, Two Pointers, Greedy
  • 설명: 리스트들에서 최소 원소를 매번 힙에서 꺼내고 다음 원소를 힙에 넣는 방식으로 k개의 연결 리스트를 합치는 힙 기반 병합 패턴이며, 각 원소를 차례로 처리하면서 전체를 정렬된 형태로 결과에 연결합니다.

📊 시간/공간 복잡도 분석

복잡도
Time O(n log k)
Space O(k)

피드백: 힙에 각 리스트의 현재 노드를 담고, 하나씩 꺼내며 연결리스트를 구성한다.

개선 제안: 현재 구현이 적절해 보입니다.

💡 풀이에 시간/공간 복잡도를 주석으로 남겨보세요!

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
38 changes: 38 additions & 0 deletions search-in-rotated-sorted-array/alphaorderly.py

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The 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
  • 패턴: Binary Search, Two Pointers
  • 설명: 회전된 정렬 배열에서 이진 탐색으로 범위를 절반씩 축소하며 target의 위치를 찾는 방식이다. left/right를 조정해 탐색 영역을 좁히는 패턴으로, 두 포인터로 구간을 관리하는 특징이 있다.

📊 시간/공간 복잡도 분석

복잡도
Time O(log n)
Space O(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
Loading