Repository navigation
[alphaorderly] WEEK 14 Solutions - #2868
Conversation
There was a problem hiding this comment.
🏷️ 알고리즘 패턴 분석
binary-tree-level-order-traversal/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)
- n: 트리의 모든 노드 개수 (각 노드를 한 번씩 방문)
공간복잡도: O(n)
- n: 최악의 경우 큐(queue)에 저장되는 노드 수(가장 마지막 레벨의 노드 수와 동일)
BFS(너비 우선 탐색)을 활용하여 트리를 레벨별로 순회하며,
각 레벨마다 노드의 값을 리스트로 모아 결과 리스트에 추가합니다.
"""
class Solution:
def levelOrder(self, root: Optional[TreeNode]) -> List[List[int]]:
if not root:
return []
queue = deque([root])
ans = []
while queue:
temp = []
Q = len(queue)
for _ in range(Q):
node = queue.popleft()
temp.append(node.val)
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
ans.append(temp)
return ans- 패턴: BFS
- 설명: 코드에서 트리를 level 단위로 순회하며 큐를 사용해 각 레벨의 노드 값을 모으는 방식으로 구현되어 BFS 패턴에 해당합니다.
📊 시간/공간 복잡도 분석
| 복잡도 | |
|---|---|
| Time | O(n) |
| Space | O(n) |
피드백: 모든 노드를 한 번 방문하고 큐에 최대 한 레벨의 노드들이 저장되므로 시간은 트리의 노드 수에 비례하고, 공간은 큐의 최대 크기와 결과 저장으로 결정됩니다.
개선 제안: 현재 구현은 일반적이고 안정적입니다. 트리의 깊이가 매우 커진 경우 큐의 크기가 커지므로 필요 시 레벨 구분 없이 인덱스 기반 순회로 최적화 고려 가능.
💡 풀이에 시간/공간 복잡도를 주석으로 남겨보세요!
There was a problem hiding this comment.
🏷️ 알고리즘 패턴 분석
counting-bits/alphaorderly.py
"""
시간복잡도: O(n)
- n: 입력된 숫자 n까지의 범위
공간복잡도: O(n)
- n: 결과값 리스트(ans)의 크기
"""
class Solution:
def countBits(self, n: int) -> List[int]:
ans = [0] * (n + 1)
for i in range(1, n + 1):
ans[i] = (i & 1) + ans[i // 2]
return ans- 패턴: Dynamic Programming, Bit Manipulation
- 설명: 정답 배열을 순차적으로 채우며 이전 값들을 이용해 현재 값을 계산하는 형태로, 비트 연산과 DP의 결합으로 각 i에 대한 비트 수를 구하는 패턴이다.
📊 시간/공간 복잡도 분석
| 복잡도 | |
|---|---|
| Time | O(n) |
| Space | O(n) |
피드백: 배열 인덱스 i에 대해 i의 하위 구조를 활용해 앞선 값을 재활용하므로 한 번의 순회로 결과를 얻습니다.
개선 제안: 현재 구현이 적절해 보입니다.
💡 풀이에 시간/공간 복잡도를 주석으로 남겨보세요!
📊 alphaorderly 님의 학습 현황이번 주 제출 문제
누적 학습 요약
문제 풀이 현황
🤖 이 댓글은 GitHub App을 통해 자동으로 작성되었습니다. 🔢 API 사용량 (gpt-5-nano)
|
There was a problem hiding this comment.
🏷️ 알고리즘 패턴 분석
house-robber-ii/alphaorderly.py
"""
시간복잡도: O(n)
- n: 입력된 배열 nums의 길이
공간복잡도: O(n)
- n: DP 리스트(first, second)의 크기
집이 원형이라 첫 집과 마지막 집을 동시에 털 수 없으므로,
두 구간으로 나누어 각각 선형 House Robber를 적용합니다.
first는 마지막 집을 제외한 구간(0 ~ n-2),
second는 첫 집을 제외한 구간(1 ~ n-1)의 최대 금액을 저장합니다.
두 구간의 마지막 값 중 더 큰 값을 반환합니다.
"""
class Solution:
def rob(self, nums: List[int]) -> int:
if len(nums) <= 2:
return max(nums)
first = [nums[0], max(nums[0], nums[1])]
second = [0, nums[1]]
for i in range(2, len(nums)):
if i != len(nums) - 1:
first.append(max(nums[i] + first[i - 2], first[i - 1]))
second.append(max(nums[i] + second[i - 2], second[i - 1]))
return max(first[-1], second[-1])- 패턴: Dynamic Programming, Greedy, Divide and Conquer
- 설명: 배열을 두 구간으로 나눠 각 구간에 대한 최적해를 구하는 DP 접근으로 최댓값을 비교합니다. 원형 배열의 특성을 이용해 선형 문제로 분해하는 아이디어는 Divide and Conquer에 부합합니다.
📊 시간/공간 복잡도 분석
| 복잡도 | |
|---|---|
| Time | O(n) |
| Space | O(n) |
피드백: 두 구간 각각 독립적으로 최적해를 구하므로 원형 제약을 회피하며 DP로 해결합니다.
개선 제안: 특정 예외 처리로 간결하게 개선될 수는 있지만 현재 구현도 적절합니다.
💡 풀이에 시간/공간 복잡도를 주석으로 남겨보세요!
There was a problem hiding this comment.
🏷️ 알고리즘 패턴 분석
meeting-rooms-ii/alphaorderly.py
"""
시간복잡도: O(n log n)
- n: 입력된 배열 intervals의 길이
공간복잡도: O(n)
- n: 진행 중인 회의의 종료 시각을 저장하는 최소 힙의 크기
intervals를 시작 시각 기준으로 정렬합니다.
최소 힙에는 아직 사용 중인 회의실의 종료 시각을 저장합니다.
각 회의의 시작 시각이 힙의 가장 이른 종료 시각 이후이면
그 회의실은 비었으므로 힙에서 제거하고,
현재 회의의 종료 시각을 힙에 넣습니다.
힙 크기의 최댓값이 필요한 최소 회의실 개수입니다.
"""
class Solution:
def minMeetingRooms(self, intervals: List[List[int]]) -> int:
intervals.sort()
ans = 1
heap = []
for start, end in intervals:
while heap and heap[0] <= start:
heappop(heap)
heappush(heap, end)
ans = max(ans, len(heap))
return ans- 패턴: Greedy, Heap / Priority Queue, Binary Search
- 설명: 이 코드는 회의실 수를 최소로 하려는 아이디어로 시작 시점 정렬 후 종료 시점 관리가 핵심인 Greedy 패턴을 활용합니다. 남은 회의실의 끝나는 시간을 최소 힙에 저장해 가장 이른 종료 시점과 비교하며 필요 시 새 회의실을 배정하므로 Heap / Priority Queue 패턴이 적용됩니다.
📊 시간/공간 복잡도 분석
| 복잡도 | |
|---|---|
| Time | O(n log n) |
| Space | O(n) |
피드백: 정렬과 힙을 활용해 겹치는 구간을 효율적으로 추적하며 최댓 힙 크기가 필요 회의실 수를 의미합니다.
개선 제안: 현 구현이 일반적으로 충분합니다. 입력 크기가 커지면 힙 연산의 상수층을 고려한 최적화 가능성은 여전히 남아 있습니다.
💡 풀이에 시간/공간 복잡도를 주석으로 남겨보세요!
There was a problem hiding this comment.
🏷️ 알고리즘 패턴 분석
word-search-ii/alphaorderly.py
"""
시간복잡도: O(w + m * n * 4^l)
- w: 모든 단어 길이의 합 (트라이 구성)
- m, n: 보드의 행, 열
- l: 단어의 최대 길이 (각 칸에서 상하좌우 DFS)
공간복잡도: O(w + l)
- w: 트라이와 정답 집합
- l: DFS 재귀 깊이와 현재 경로의 방문 집합
단어를 트라이에 넣은 뒤, 보드의 각 칸에서 DFS로 이어지는 단어를 찾습니다.
이미 찾은 단어는 is_end를 끄고, 더 이상 이어지지 않는 노드는 트라이에서 지워
같은 접두사를 다시 탐색하지 않습니다.
"""
class TrieNode:
def __init__(self):
self.is_end = False
self.children = dict()
def add_word(self, word: str):
node = self
for ch in word:
if ch not in node.children:
node.children[ch] = TrieNode()
node = node.children[ch]
# 이 글자에서 단어가 끝난다
node.is_end = True
class Solution:
def findWords(self, board: list[list[str]], words: list[str]) -> list[str]:
ROW, COL = len(board), len(board[0])
# 상하좌우
DIR = [[1, 0], [0, 1], [-1, 0], [0, -1]]
trie = TrieNode()
for word in words:
trie.add_word(word)
def bound(row: int, col: int) -> bool:
return 0 <= row < ROW and 0 <= col < COL
# ans: 찾은 단어, visited: 현재 경로에서 지난 칸
ans, visited = set(), set()
def search(r: int, c: int, node: TrieNode, word: str):
# 다음 글자가 트라이에 없거나, 같은 칸을 다시 밟으면 중단
if board[r][c] not in node.children or (r, c) in visited:
return
visited.add((r, c))
# 가지치기할 때 부모에서 현재 글자를 지우기 위해 보관
parent = node
ch = board[r][c]
node = node.children[ch]
word += ch
if node.is_end:
ans.add(word)
# 같은 단어는 한 번만 찾는다
node.is_end = False
for dr, dc in DIR:
tr, tc = r + dr, c + dc
if not bound(tr, tc):
continue
search(tr, tc, node, word)
# 백트래킹: 이 칸을 다른 경로에서 다시 쓸 수 있게 되돌린다
visited.remove((r, c))
# 자식도 없고 여기서 끝나는 단어도 없으면 트라이에서 제거
if not node.children and not node.is_end:
del parent.children[ch]
for r in range(ROW):
for c in range(COL):
search(r, c, trie, "")
return list(ans)- 패턴: Trie, Backtracking, Depth-First Search, Hash Map / Hash Set
- 설명: 트라이를 구성해 단어를 저장하고 보드에서 DFS로 탐색하며 경로를 백트래킹합니다. 방문 관리와 가지치기, 중간 노드 삭제를 통해 효율적으로 가능한 단어를 찾는 구조로, DFS 기반의 백트래킹 패턴이 핵심입니다.
📊 시간/공간 복잡도 분석
| 복잡도 | |
|---|---|
| Time | O(w + m * n * 4^l) |
| Space | O(w + l) |
피드백: 사전 구성된 트라이와 가지치기로 중복 탐색을 줄이며 DFS를 통해 보드 전체를 탐색합니다.
개선 제안: 현재 아이디어가 효과적이지만, 트라이 제거 및 재탐색 비용을 더 줄일 수 있는 추가 최적화 여지가 있습니다.
💡 풀이에 시간/공간 복잡도를 주석으로 남겨보세요!
DaleSeo
left a comment
There was a problem hiding this comment.
추선 연휴에도 거르지 않고 문제푸는 모습 멋집니다! 👍
| for c in range(COL): | ||
| search(r, c, trie, "") | ||
|
|
||
| return list(ans) |
There was a problem hiding this comment.
굳이 ans에 세트를 할당하고 마지막에 다시 리스트로 바꿀 이유가 있을까요? 같은 단어가 다시 추가될 수 있는 경우가 있는지 생각해보시면 좋을 것 같습니다.
| 시간복잡도: O(n) | ||
| - n: 입력된 배열 nums의 길이 | ||
| 공간복잡도: O(n) | ||
| - n: DP 리스트(first, second)의 크기 |
There was a problem hiding this comment.
점화식을 보면 길이가 n인 리스트 대신에 변수 2개만 있어도 충분할 것 같네요? 메모리 최적화의 기회가 보입니다.
| for i in range(2, len(nums)): | ||
| if i != len(nums) - 1: | ||
| first.append(max(nums[i] + first[i - 2], first[i - 1])) | ||
| second.append(max(nums[i] + second[i - 2], second[i - 1])) |
There was a problem hiding this comment.
하나의 루프에서 두 가지 동작을 하네요. prev2, prev1 변수를 사용하는 하나의 헬퍼 함수를 두면 공간 복잡도가 O(1)로 줄고 가독성도 개선할 수 있을 거 같습니다.
답안 제출 문제
작성자 체크 리스트
In Review로 설정해주세요.검토자 체크 리스트
Important
본인 답안 제출 뿐만 아니라 다른 분 PR 하나 이상을 반드시 검토를 해주셔야 합니다!