Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
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
72 changes: 72 additions & 0 deletions coin-change/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.

🏷️ 알고리즘 패턴 분석

  • 패턴: Dynamic Programming
  • 설명: 코인 교환 문제는 목표 금액을 구성하는 최소 동전 수를 부분 문제로 나누고, 재귀/반복으로 최적 해를 구성하는 DP 패턴(Top-Down 및 Bottom-Up, 및 공간 최적화)이 사용됩니다.

📊 시간/공간 복잡도 분석

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

풀이 1: Solution.coinChange — Time: O(n * amount) / Space: O(n * amount)
복잡도
Time O(n * amount)
Space O(n * amount)

피드백: 하나의 금액에 대해 각 코인 위치별로 서브문제를 cache로 재사용하여 중복을 제거합니다.

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

풀이 2: Solution.coinChange — Time: O(n * amount) / Space: O(n * amount)
복잡도
Time O(n * amount)
Space O(n * amount)

피드백: 코인 인덱스와 남은 금액의 조합을 상태로 하여 모든 경우를 탐색합니다.

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

풀이 3: Solution.coinChange — Time: O(n * amount) / Space: O(amount)
복잡도
Time O(n * amount)
Space O(amount)

피드백: 거기에 코인 순회를 바꿔가며 가능한 최소 개수를 갱신합니다. 추가 공간 절약이 가능해졌습니다.

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

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

Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
"""
Time Complexity: O(n * amount)
Space Complexity: O(n * amount)

- DP / Top-Down approach
- Use a cache to store the results of the subproblems
"""
class Solution:
def coinChange(self, coins: List[int], amount: int) -> int:
LARGE = 10 ** 5

@cache
def dp(coin: int, left: int) -> int:
if left == 0:
return 0

if left < 0 or coin >= len(coins):
return LARGE

a = dp(coin, left - coins[coin]) + 1
b = dp(coin + 1, left)

return min(a, b)

ans = dp(0, amount)

return ans if ans != LARGE else -1

"""
Time Complexity: O(n * amount)
Space Complexity: O(n * amount)

- DP / Bottom-Up approach
- Use a 2D array to store the results of the subproblems
"""
class Solution:
def coinChange(self, coins: List[int], amount: int) -> int:
N = len(coins)
dp = [[float('inf')] * (amount + 1) for _ in range(N)]

for c in range(N):
dp[c][0] = 0

if c > 0:
for a in range(amount + 1):
dp[c][a] = dp[c - 1][a]

for a in range(coins[c], amount + 1):
dp[c][a] = min(dp[c][a], dp[c][a - coins[c]] + 1)

ans = dp[-1][-1]

return ans if ans != float('inf') else -1

"""
Time Complexity: O(n * amount)
Space Complexity: O(amount)

- DP / Bottom-Up approach [Space Optimized]
- Use a 1D array to store the results of the subproblems
"""
class Solution:
def coinChange(self, coins: List[int], amount: int) -> int:
N = len(coins)
dp = [float("inf")] * (amount + 1)
dp[0] = 0

for c in range(N):
for a in range(coins[c], amount + 1):
dp[a] = min(dp[a], dp[a - coins[c]] + 1)

return dp[-1] if dp[-1] != float("inf") else -1
40 changes: 40 additions & 0 deletions find-minimum-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.

🏷️ 알고리즘 패턴 분석

  • 패턴: Binary Search
  • 설명: 코드의 핵심은 회전된 정렬 배열에서 이진 탐색을 이용해 최소값의 위치를 찾는 방식이다. left, right를 이용한 분할과 mid 비교로 O(log N) 탐색을 구현한다.

📊 시간/공간 복잡도 분석

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

풀이 1: Solution.findMin — Time: O(log N) / Space: O(1)
복잡도
Time O(log N)
Space O(1)

피드백: 양쪽 끝과 중간 값을 비교해 최소값의 위치를 이진 탐색으로 좁힙니다.

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

풀이 2: Solution.findMin — Time: O(N) / Space: O(1)
복잡도
Time O(N)
Space O(1)

피드백: 최적의 풀이가 아니므로 테스트용 대안으로 남겨둔 형태입니다.

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

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

Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
"""
Time Complexity: O(log N)
Space Complexity: O(1)

### Binary Search Solution ###

1. Initialize two pointers, left and right, to the start and end of the array
2. While left is less than right, calculate the middle index
3. If nums[mid] > nums[right], search the right half (left = mid + 1)
- Why? mid is in the left sorted portion (larger values), so the rotation point (minimum) must be to the right of mid
4. Otherwise, search the left half including mid (right = mid)
- nums[mid] <= nums[right] means mid is in the right sorted portion or the array is not rotated, so the minimum is at mid or to its left
5. When left == right, return nums[right]
"""
class Solution:
def findMin(self, nums: List[int]) -> int:
N = len(nums)
left, right = 0, N - 1

while left < right:
mid = (left + right) // 2

if nums[mid] > nums[right]:
left = mid + 1
else:
right = mid

return nums[right]

"""
Time Complexity: O(N)
Space Complexity: O(1)

### Linear Search Solution ### ( NOT RECOMMENDED )

1. Return the minimum element in the array
"""
class Solution:
def findMin(self, nums: List[int]) -> int:
return min(nums)
122 changes: 122 additions & 0 deletions maximum-depth-of-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.

🏷️ 알고리즘 패턴 분석

  • 패턴: Binary Search, Depth First Search, Breadth First Search, Queue, Stack, Greedy, Dynamic Programming, Two Pointers, Sliding Window, Backtracking, Monotonic Stack, Heap / Priority Queue, Hash Map / Hash Set, Divide and Conquer, Union Find, Trie, Bit Manipulation
  • 설명: 이 코드는 이진 트리의 깊이를 구하는 문제로, DFS(재귀 및 스택 이용), BFS/레벨 순회 큐 방식 등 여러 traversal 방식이 제시되어 있습니다. 트리 순회 패턴과 깊이 계산은 대표적인 DFS/BFS 패턴에 속합니다.

📊 시간/공간 복잡도 분석

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

풀이 1: Solution.maxDepth — Time: O(N) / Space: O(N)
복잡도
Time O(N)
Space O(N)

피드백: 노드 수에 비례하는 재귀 스택을 사용합니다.

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

풀이 2: Solution.maxDepth — Time: O(N) / Space: O(N)
복잡도
Time O(N)
Space O(N)

피드백: 명시적 스택으로 깊이를 추적합니다.

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

풀이 3: Solution.maxDepth — Time: O(N) / Space: O(N)
복잡도
Time O(N)
Space O(N)

피드백: 큐를 사용해 레벨별로 깊이를 업데이트합니다.

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

풀이 4: Solution.maxDepth — Time: O(N) / Space: O(N)
복잡도
Time O(N)
Space O(N)

피드백: 최종 깊이를 레벨 변수로 추적하는 BFS 변형입니다.

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

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

Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
# 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
"""
Time Complexity: O(N)
Space Complexity: O(N) - Recursive stack space

### Recursive Solution ( DFS ) ###

1. If the root is None, return 0
2. Return the maximum of the depth of the left and right subtrees + 1
"""
class Solution:
def maxDepth(self, root: Optional[TreeNode]) -> int:
if not root:
return 0

return max(self.maxDepth(root.left), self.maxDepth(root.right)) + 1

"""
Time Complexity: O(N)
Space Complexity: O(N) - Stack space

### Iterative Solution ( DFS ) ###

1. If the root is None, return 0
2. Use a stack to store the nodes and the level of the nodes
3. Pop the nodes from the stack and update the maximum depth
4. If the node has a left child, add the left child and the level + 1 to the stack
5. If the node has a right child, add the right child and the level + 1 to the stack
6. Return the maximum depth
"""
class Solution:
def maxDepth(self, root: Optional[TreeNode]) -> int:
if not root:
return 0

s = [(root, 1)]
ans = 1

while s:
node, level = s.pop()
ans = max(ans, level)

if node.left:
s.append((node.left, level + 1))

if node.right:
s.append((node.right, level + 1))

return ans

"""
Time Complexity: O(N)
Space Complexity: O(N) - Queue space

### Iterative Solution ( BFS ) ###

1. If the root is None, return 0
2. Use a queue to store the nodes and the level of the nodes
3. Pop the nodes from the queue and update the maximum depth
4. If the node has a left child, add the left child and the level + 1 to the queue
5. If the node has a right child, add the right child and the level + 1 to the queue
6. Return the maximum depth
"""
class Solution:
def maxDepth(self, root: Optional[TreeNode]) -> int:
if not root:
return 0

q = deque([(root, 1)])
ans = 1

while q:
node, level = q.popleft()
ans = max(ans, level)

if node.left:
q.append((node.left, level + 1))

if node.right:
q.append((node.right, level + 1))

return ans

"""
Time Complexity: O(N)
Space Complexity: O(N) - Queue space

### Iterative Solution ( Level Order Traversal ) ###

1. If the root is None, return 0
2. Use a queue to store the nodes
3. Pop the nodes from the queue and update the maximum depth
4. If the node has a left child, add the left child to the queue
5. If the node has a right child, add the right child to the queue
6. Return the maximum depth
"""
class Solution:
def maxDepth(self, root: Optional[TreeNode]) -> int:
if not root:
return 0

q = deque([root])
level = 0

while q:
level += 1
N = len(q)
for _ in range(N):
node = q.popleft()

if node.left:
q.append(node.left)

if node.right:
q.append(node.right)

return level
57 changes: 57 additions & 0 deletions merge-two-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.

🏷️ 알고리즘 패턴 분석

  • 패턴: Two Pointers, Merge Two Sorted Lists is typically solved with a pointer-based approach, Dynamic Programming
  • 설명: 리스트를 순차적으로 비교하며 포인터를 이동하는 구조로 두 정렬 리스트를 합치는 방식이므로 Two Pointers 패턴에 해당합니다. 재귀 버전 역시 포인터를 따라 연결을 구성하는 방식으로 구현됩니다.

📊 시간/공간 복잡도 분석

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

풀이 1: Solution.mergeTwoLists — Time: O(N) / Space: O(1)
복잡도
Time O(N)
Space O(1)

피드백: 더미 노드를 사용해 일관된 연결을 유지합니다.

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

풀이 2: Solution.mergeTwoLists — Time: O(N) / Space: O(N)
복잡도
Time O(N)
Space O(N)

피드백: 재귀 깊이가 증가할 경우 스택 사용이 늘어납니다.

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

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

Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
"""
Time Complexity: O(N)
Space Complexity: O(1)

1. Create a dummy node to store the head of the merged list ( return_node )
2. Traverse the two lists until one of the lists is empty
3. Compare the values of the two nodes and add the smaller node to the dummy node
4. Move the pointer of the list with the smaller node to the next node
5. Add the remaining nodes of the non-empty list to the dummy node
6. Return the next node of the dummy node
"""
class Solution:
def mergeTwoLists(
self, list1: Optional[ListNode], list2: Optional[ListNode]
) -> Optional[ListNode]:
head = ListNode()
node = head

while list1 and list2:
if list1.val > list2.val:
head.next = list2
list2 = list2.next
else:
head.next = list1
list1 = list1.next

head = head.next

head.next = list1 or list2

return node.next

"""
Time Complexity: O(N)
Space Complexity: O(N) - Recursive stack space

1. If one of the lists is empty, return the other list
2. Compare the values of the two nodes and add the smaller node to the merged list
3. Move the pointer of the list with the smaller node to the next node
4. Return the next node of the merged list
"""
class Solution:
def mergeTwoLists(self, list1: Optional[ListNode], list2: Optional[ListNode]) -> Optional[ListNode]:
if not list1 or not list2:
return list1 or list2

if list1.val > list2.val:
list2.next = self.mergeTwoLists(list1, list2.next)
return list2
else:
list1.next = self.mergeTwoLists(list1.next, list2)
return list1
Loading
Loading