Skip to content
Merged
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
37 changes: 37 additions & 0 deletions binary-tree-level-order-traversal/dolphinflow86.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-tree-level-order-traversal/dolphinflow86.py
# N is the total number of nodes in the binary tree.
# TC: O(N) - each node is visited and enqueued/dequeued once
# SC: O(N) - queue stores at most the maximum width of the tree (up to N / 2 nodes)

from collections import deque
from typing import List, Optional


# 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


class Solution:

    def levelOrder(self, root: Optional["TreeNode"]) -> List[List[int]]:
        if not root:
            return []

        levels = []
        queue = deque([root])

        while queue:
            level_vals = []
            for _ in range(len(queue)):
                node = queue.popleft()
                level_vals.append(node.val)
                if node.left:
                    queue.append(node.left)
                if node.right:
                    queue.append(node.right)
            levels.append(level_vals)

        return levels
  • 패턴: Breadth-First Search, Hash Map / Hash Set
  • 설명: 레벨별로 노드를 순회하며 큐를 이용해 넓이우선순회(BFS)를 구현한 코드입니다. 각 레벨의 노드를 큐에서 꺼내고 자식 노드를 큐에 추가하는 방식으로 전체 트리를 레벨 단위로 탐색합니다.

📊 시간/공간 복잡도 분석

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

피드백: 너비 우선 탐색으로 모든 노드를 한 번씩 방문하고 큐에 저장하므로 시간은 트리의 노드 수에 비례한다. 추가 공간은 큐와 결과 리스트에 의해 선형이다.

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

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

Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# N is the total number of nodes in the binary tree.
# TC: O(N) - each node is visited and enqueued/dequeued once
# SC: O(N) - queue stores at most the maximum width of the tree (up to N / 2 nodes)

from collections import deque
from typing import List, Optional


# 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


class Solution:

def levelOrder(self, root: Optional["TreeNode"]) -> List[List[int]]:
if not root:
return []

levels = []
queue = deque([root])

while queue:
level_vals = []
for _ in range(len(queue)):
node = queue.popleft()
level_vals.append(node.val)
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
levels.append(level_vals)

return levels
14 changes: 14 additions & 0 deletions counting-bits/dolphinflow86.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.

🏷️ 알고리즘 패턴 분석

counting-bits/dolphinflow86.py
# N is the given integer.
# TC: O(N) - single pass from 0 to N using previous subproblem results
# SC: O(1) - auxiliary space (O(N) to store the result array)

from typing import List


class Solution:

    def countBits(self, n: int) -> List[int]:
        ans = [0] * (n + 1)
        for i in range(1, n + 1):
            ans[i] = ans[i >> 1] + (i & 1)
        return ans
  • 패턴: Dynamic Programming, Bit Manipulation
  • 설명: 주어진 수들의 이진 비트 수를 이전 결과를 이용해 계산하는 DP 접근과 비트 연산(i >> 1, i & 1)을 활용한 방법으로, 한 번의 순회로 모든 값을 구합니다.

📊 시간/공간 복잡도 분석

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

피드백: i의 이진 표현의 최하위 비트를 제거한 값에 1의 개수를 더하는 DP 방식으로 각 i에 대해 답을 빠르게 구한다.

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

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

Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# N is the given integer.
# TC: O(N) - single pass from 0 to N using previous subproblem results
# SC: O(1) - auxiliary space (O(N) to store the result array)

from typing import List


class Solution:

def countBits(self, n: int) -> List[int]:
ans = [0] * (n + 1)
for i in range(1, n + 1):
ans[i] = ans[i >> 1] + (i & 1)
return ans
22 changes: 22 additions & 0 deletions house-robber-ii/dolphinflow86.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.

🏷️ 알고리즘 패턴 분석

house-robber-ii/dolphinflow86.py
# N is the number of houses.
# TC: O(N) - two passes of linear house robber (excluding first or last house)
# SC: O(1) - constant auxiliary space tracking two variables for DP

from typing import List


class Solution:

    def rob(self, nums: List[int]) -> int:
        if not nums:
            return 0
        if len(nums) <= 2:
            return max(nums)

        def rob_linear(houses: List[int]) -> int:
            prev2, prev1 = 0, 0
            for money in houses:
                prev2, prev1 = prev1, max(prev1, prev2 + money)
            return prev1

        return max(rob_linear(nums[:-1]), rob_linear(nums[1:]))
  • 패턴: Dynamic Programming, Two Pointers
  • 설명: 이 코드는 원형 배열에서의 집털이 문제를 부분적으로 선형으로 나눠 DP로 최대값을 구하는 방식으로 작동합니다. 연속 두 선택의 최댓값을 유지하는 DP 패턴과 두 구간으로 나눠 비교하는 접근이 핵심이며, 선형 탐색으로 상태를 갱신합니다.

📊 시간/공간 복잡도 분석

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

피드백: 두 개의 선형 다이내믹 프로그래밍 호출을 통해 원형 구조를 처리한다. 공간은 상수로 유지된다.

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

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

Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# N is the number of houses.
# TC: O(N) - two passes of linear house robber (excluding first or last house)
# SC: O(1) - constant auxiliary space tracking two variables for DP

from typing import List


class Solution:

def rob(self, nums: List[int]) -> int:
if not nums:
return 0
if len(nums) <= 2:
return max(nums)

def rob_linear(houses: List[int]) -> int:
prev2, prev1 = 0, 0
for money in houses:
prev2, prev1 = prev1, max(prev1, prev2 + money)
return prev1
Comment on lines +17 to +20

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

prev2, prev1 을 사용하니 로직이 더 명확하게 보이네요.


return max(rob_linear(nums[:-1]), rob_linear(nums[1:]))
32 changes: 32 additions & 0 deletions meeting-rooms-ii/dolphinflow86.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.

🏷️ 알고리즘 패턴 분석

meeting-rooms-ii/dolphinflow86.py
# N is the number of meeting intervals.
# TC: O(N log N) - sorting intervals by start time and maintaining a min-heap
# SC: O(N) - heap stores at most N end times in the worst case

import heapq
from typing import Any, List


class Solution:

    def minMeetingRooms(self, intervals: List[Any]) -> int:
        if not intervals:
            return 0

        # Support both List[List[int]] and List[Interval]
        def get_interval(item):
            if hasattr(item, "start") and hasattr(item, "end"):
                return item.start, item.end
            return item[0], item[1]

        normalized = [get_interval(interval) for interval in intervals]
        normalized.sort(key=lambda x: x[0])

        min_heap = []
        for start, end in normalized:
            if min_heap and min_heap[0] <= start:
                heapq.heappop(min_heap)
            heapq.heappush(min_heap, end)

        return len(min_heap)

    min_meeting_rooms = minMeetingRooms
  • 패턴: Min-Heap / Priority Queue, Two Pointers, Greedy
  • 설명: 회의실 배정 문제를 해결하며 시작 시간 오름차순 정렬 후, 종료 시점을 최소 힙에 관리하여 겹치는 구간 수를 계산합니다. 힙의 맨위 값으로 남은 회의의 종료 시점을 관리하는 방식이 핵심 패턴입니다.

📊 시간/공간 복잡도 분석

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

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

피드백: 회의 시작과 종료를 정렬하고, 종료 시점을 관리하는 힙으로 최댓 필요 방의 수를 계산한다.

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

풀이 2: Solution.minMeetingRooms — Time: O(n log n) / Space: O(n)
복잡도
Time O(n log n)
Space O(n)

피드백: 헤더가 중복으로 보이는 주석적 라인으로 보이나 본문 기능에는 영향 없음.

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

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

Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# N is the number of meeting intervals.
# TC: O(N log N) - sorting intervals by start time and maintaining a min-heap
# SC: O(N) - heap stores at most N end times in the worst case

import heapq
from typing import Any, List


class Solution:

def minMeetingRooms(self, intervals: List[Any]) -> int:
if not intervals:
return 0

# Support both List[List[int]] and List[Interval]
def get_interval(item):
if hasattr(item, "start") and hasattr(item, "end"):
return item.start, item.end
return item[0], item[1]

normalized = [get_interval(interval) for interval in intervals]
normalized.sort(key=lambda x: x[0])

min_heap = []
for start, end in normalized:
if min_heap and min_heap[0] <= start:
heapq.heappop(min_heap)
heapq.heappush(min_heap, end)

return len(min_heap)

min_meeting_rooms = minMeetingRooms
59 changes: 59 additions & 0 deletions word-search-ii/dolphinflow86.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.

🏷️ 알고리즘 패턴 분석

word-search-ii/dolphinflow86.py
# M, N are dimensions of the board, W is the number of words, and L is the maximum length of a word.
# TC: O(W * L + M * N * 3^(L - 1)) - building Trie takes O(W * L); backtracking explores at most 3 directions after first step up to depth L
# SC: O(W * L) - Trie storage for all words and recursion stack depth up to L

from typing import List


class TrieNode:

    def __init__(self):
        self.children = {}
        self.word = None


class Solution:

    def findWords(self, board: List[List[str]], words: List[str]) -> List[str]:
        root = TrieNode()
        for word in words:
            node = root
            for char in word:
                if char not in node.children:
                    node.children[char] = TrieNode()
                node = node.children[char]
            node.word = word

        rows, cols = len(board), len(board[0])
        result = []

        def dfs(r: int, c: int, parent: TrieNode):
            char = board[r][c]
            curr_node = parent.children.get(char)
            if not curr_node:
                return

            if curr_node.word:
                result.append(curr_node.word)
                curr_node.word = None

            board[r][c] = "#"  # mark visited

            for dr, dc in ((-1, 0), (1, 0), (0, -1), (0, 1)):
                nr, nc = r + dr, c + dc
                if 0 <= nr < rows and 0 <= nc < cols and board[nr][nc] != "#":
                    if board[nr][nc] in curr_node.children:
                        dfs(nr, nc, curr_node)

            board[r][c] = char  # backtrack

            # Prune leaf nodes to accelerate search
            if not curr_node.children:
                del parent.children[char]

        for r in range(rows):
            for c in range(cols):
                if board[r][c] in root.children:
                    dfs(r, c, root)

        return result
  • 패턴: Trie, Backtracking, Depth-First Search
  • 설명: 트라이를 구축하고 보드에서 DFS로 백트래킹하며 단어를 탐색한다. 트라이를 통해 접두어를 빠르게 체크하고, DFS로 인접 4방향으로 탐색해 단어를 찾고, 방문 표시와 백트랙으로 원상태를 복구한다.

📊 시간/공간 복잡도 분석

복잡도
Time O(s + total_cells)
Space O(sum of Trie nodes + board size)

피드백: 전형적인 Trie+DFS 접근으로 여러 단어를 한 번에 탐색한다. 백트래킹과 트라이 가지치기로 실사용에서 효율을 높인다.

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

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

Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# M, N are dimensions of the board, W is the number of words, and L is the maximum length of a word.
# TC: O(W * L + M * N * 3^(L - 1)) - building Trie takes O(W * L); backtracking explores at most 3 directions after first step up to depth L
# SC: O(W * L) - Trie storage for all words and recursion stack depth up to L

from typing import List


class TrieNode:

def __init__(self):
self.children = {}
self.word = None


class Solution:

def findWords(self, board: List[List[str]], words: List[str]) -> List[str]:
root = TrieNode()
for word in words:
node = root
for char in word:
if char not in node.children:
node.children[char] = TrieNode()
node = node.children[char]
node.word = word

rows, cols = len(board), len(board[0])
result = []

def dfs(r: int, c: int, parent: TrieNode):
char = board[r][c]
curr_node = parent.children.get(char)
if not curr_node:
return

if curr_node.word:
result.append(curr_node.word)
curr_node.word = None

board[r][c] = "#" # mark visited

for dr, dc in ((-1, 0), (1, 0), (0, -1), (0, 1)):
nr, nc = r + dr, c + dc
if 0 <= nr < rows and 0 <= nc < cols and board[nr][nc] != "#":
if board[nr][nc] in curr_node.children:
dfs(nr, nc, curr_node)

board[r][c] = char # backtrack

# Prune leaf nodes to accelerate search
if not curr_node.children:
del parent.children[char]

for r in range(rows):
for c in range(cols):
if board[r][c] in root.children:
dfs(r, c, root)

return result
Loading