[dolphinflow86] WEEK 07 Solutions - #2799
Conversation
There was a problem hiding this comment.
🏷️ 알고리즘 패턴 분석
longest-substring-without-repeating-characters/dolphinflow86.py
# N is the length of s.
# TC: O(N) - each character is added and removed at most once
# SC: O(N) - stores the characters in the current window
class Solution:
def lengthOfLongestSubstring(self, s: str) -> int:
chars = set()
left = 0
longest = 0
for right, char in enumerate(s):
while char in chars:
chars.remove(s[left])
left += 1
chars.add(char)
longest = max(longest, right - left + 1)
return longest
- 패턴: Sliding Window, Hash Map / Hash Set
- 설명: 문자열에서 중복 제거를 위해 창을 움직이며(left, right) 현재 윈도우의 문자들을 집합에 저장하고, 중복 시 왼쪽 포인터를 이동시키는 슬라이딩 윈도우 패턴을 사용합니다. 해시 세트를 이용해 문자 존재 여부를 확인합니다.
📊 시간/공간 복잡도 분석
| 복잡도 | |
|---|---|
| Time | O(n) |
| Space | O(min(n, m)) |
피드백: 해당 구현은 모든 문자를 한 번씩 추가/제거하며 윈도우를 이동시키므로 선형 시간과 창 크기에 비례한 추가 공간을 사용한다.
개선 제안: 현재 구현이 적절해 보입니다.
💡 풀이에 시간/공간 복잡도를 주석으로 남겨보세요!
📊 dolphinflow86 님의 학습 현황이번 주 제출 문제
누적 학습 요약
문제 풀이 현황
🤖 이 댓글은 GitHub App을 통해 자동으로 작성되었습니다. 🔢 API 사용량 (gpt-5-nano)
|
There was a problem hiding this comment.
🏷️ 알고리즘 패턴 분석
number-of-islands/dolphinflow86.py
# R is the number of rows, and C is the number of columns.
# TC: O(R * C) - visits each cell at most once
# SC: O(R * C) - uses the recursion stack in the worst case
class Solution:
def numIslands(self, grid: List[List[str]]) -> int:
rows = len(grid)
cols = len(grid[0])
def dfs(row, col):
if (
row < 0
or row >= rows
or col < 0
or col >= cols
or grid[row][col] != "1"
):
return
grid[row][col] = "0"
dfs(row - 1, col)
dfs(row + 1, col)
dfs(row, col - 1)
dfs(row, col + 1)
islands = 0
for row in range(rows):
for col in range(cols):
if grid[row][col] == "1":
islands += 1
dfs(row, col)
return islands
- 패턴: Depth-First Search, Backtracking
- 설명: 그리드에서 1로 연결된 영역을 DFS로 탐색하며 방문한 노드를 0으로 바꿔 연결 요소(섬)의 개수를 셈. 재귀를 이용한 깊은 탐색이 핵심 패턴입니다.
📊 시간/공간 복잡도 분석
| 유저 분석 | 실제 분석 | 결과 | |
|---|---|---|---|
| Time | O(R * C) | O(rows * cols) | ❌ |
| Space | O(R * C) | O(rows * cols) | ❌ |
피드백: 그리드의 각 셀을 한 번씩 방문하고 인접한 '1'들을 재귀적으로 처리한다.
개선 제안: 재귀 깊이가 커질 수 있는 환경에서는 스택 기반 DFS나 BFS로 스택 사용을 명시하는 것이 안전하다.
There was a problem hiding this comment.
🏷️ 알고리즘 패턴 분석
reverse-linked-list/dolphinflow86.py
# TC: O(N) - visits each node exactly once
# SC: O(1) - reverses the links in place
class Solution:
def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
prev = None
current = head
while current:
next_node = current.next
current.next = prev
prev = current
current = next_node
return prev
- 패턴: Two Pointers, Linked List
- 설명: 주어진 코드는 단순히 포인터 두 개를 사용해 링크드 리스트의 방향을 반대로 바꾸는 과정으로, 노드를 순회하며 노드의 링크를 뒤집는 데 두 포인터를 활용하는 패턴이 핵심입니다. 시간 복잡도 O(N), 공간 복잡도 O(1)로 구현됩니다.
📊 시간/공간 복잡도 분석
| 복잡도 | |
|---|---|
| Time | O(n) |
| Space | O(1) |
피드백: 연결 구조를 역전시키면서 상호 참조를 유지하는 표준 패턴이다.
개선 제안: 현재 구현이 적절해 보입니다.
💡 풀이에 시간/공간 복잡도를 주석으로 남겨보세요!
There was a problem hiding this comment.
제 개인적인 생각에는요! head를 리턴 혹은 어디에도 쓰지 않으니 current를 쓰시는 부분 그대로 head를 쓰셔도 되지 않을까?
하는 생각이 들어요!
그리고 파이썬의 a, b = b, a처럼 쓸수 있는 문법을 활용하시면 while loop 안을 1줄로 줄이실수도 있답니다!
There was a problem hiding this comment.
오 그렇네요!
리뷰 받으면서 파이썬 문법에 조금씩 익숙해지는 것 같습니다.
리뷰 감사합니다.
| if ( | ||
| row < 0 | ||
| or row >= rows | ||
| or col < 0 | ||
| or col >= cols | ||
| or grid[row][col] != "1" | ||
| ): |
There was a problem hiding this comment.
python의 a <= x < b 쓰면 이런 형태도 가능한데 or 사용해주신게 더 명확한 거 같기는 하네요.
if not (
0 <= row < rows
and 0 <= col < cols
and grid[row][col] == "1"
):
| rows = len(grid) | ||
| cols = len(grid[0]) |
There was a problem hiding this comment.
rows, cols가 길이로 보이지 않고 배열 같은 변수가 담기는 거처럼 보이는 거 같습니다. 길이를 나타내는 네이밍을 사용하시면 어떨까요?
| current = head | ||
|
|
||
| while current: | ||
| next_node = current.next | ||
| current.next = prev | ||
| prev = current | ||
| current = next_node |
There was a problem hiding this comment.
next가 예약어여서 _node를 붙여주신 거 같네요. 다른 네이밍들이랑 일관성을 맞추시는 건 어떨까요?
| while char in chars: | ||
| chars.remove(s[left]) | ||
| left += 1 |
There was a problem hiding this comment.
left를 하나씩 증가하지 않고 각 문자의 인덱스를 저장해서 점프하는 방식으로도 조금 더 최적화가 가능하니 풀어보셔도 좋을 거 같습니다.
There was a problem hiding this comment.
🏷️ 알고리즘 패턴 분석
longest-substring-without-repeating-characters/dolphinflow86.py
# N is the length of s.
# TC: O(N) - each character is added and removed at most once
# SC: O(N) - stores the characters in the current window
class Solution:
def lengthOfLongestSubstring(self, s: str) -> int:
chars = set()
left = 0
longest = 0
for right, char in enumerate(s):
while char in chars:
chars.remove(s[left])
left += 1
chars.add(char)
longest = max(longest, right - left + 1)
return longest- 패턴: Sliding Window, Hash Map / Hash Set
- 설명: 문자열에서 연속 부분 문자열의 길이를 구하기 위해 두 포인터(left, right)로 창(window)을 유지하고, 집합으로 현재 창의 문자들을 관리하는 슬라이딩 윈도우 패턴을 사용합니다. 해시 세트를 활용해 등장 여부를 빠르게 확인합니다.
📊 시간/공간 복잡도 분석
| 유저 분석 | 실제 분석 | 결과 | |
|---|---|---|---|
| Time | O(N) | O(n) | ✅ |
| Space | O(N) | O(min(n, k)) | ❌ |
피드백: 두 인덱스가 한 방향으로 움직이며 각 문자를 셋에 저장하고 제거한다. 각 문자는 한 번씩 추가/제거되므로 선형 시간 복잡도에 도달한다.
개선 제안: 현재 구현이 적합해 보입니다.
There was a problem hiding this comment.
🏷️ 알고리즘 패턴 분석
number-of-islands/dolphinflow86.py
# R is the number of rows, and C is the number of columns.
# TC: O(R * C) - visits each cell at most once
# SC: O(R * C) - uses the recursion stack in the worst case
class Solution:
def numIslands(self, grid: List[List[str]]) -> int:
row_count = len(grid)
column_count = len(grid[0])
def dfs(row, col):
if (
row < 0
or row >= row_count
or col < 0
or col >= column_count
or grid[row][col] != "1"
):
return
grid[row][col] = "0"
dfs(row - 1, col)
dfs(row + 1, col)
dfs(row, col - 1)
dfs(row, col + 1)
island_count = 0
for row in range(row_count):
for col in range(column_count):
if grid[row][col] == "1":
island_count += 1
dfs(row, col)
return island_count- 패턴: Depth-First Search, Backtracking
- 설명: 그리드의 연결된 1들을 탐색하기 위해 DFS를 재귀로 호출하여 방문 표시를 하고, 섬의 개수를 셈. 각 섬의 모든 칸을 탐색하는 과정은 백트래킹 성격도 포함합니다.
📊 시간/공간 복잡도 분석
| 유저 분석 | 실제 분석 | 결과 | |
|---|---|---|---|
| Time | O(R * C) | O(R*C) | ✅ |
| Space | O(R * C) | O(R*C) | ✅ |
피드백: 그리드 전체를 한 번씩 방문하고 각 섬에 대해 DFS로 인접한 부분을 방문한다.
개선 제안: 현재 구현이 적절해 보입니다.
There was a problem hiding this comment.
🏷️ 알고리즘 패턴 분석
reverse-linked-list/dolphinflow86.py
# TC: O(N) - visits each node exactly once
# SC: O(1) - reverses the links in place
class Solution:
def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
prev = None
current = head
while current:
next_node = current.next
current.next = prev
prev = current
current = next_node
return prev- 패턴: Two Pointers, Linked List
- 설명: 주어진 코드는 포인터 두 개를 사용해 연결리스트의 노드를 역순으로 만듭니다. 각 노드를 한 번씩 방문하며 노드 간 링크를 뒤집는 방식으로 O(N) 시간, O(1) 추가 공간으로 구현됩니다.
📊 시간/공간 복잡도 분석
| 복잡도 | |
|---|---|
| Time | O(n) |
| Space | O(1) |
피드백: 순회 중 현재 노드의 다음 노드를 저장하고 포인터를 뒤로 바꿔 간다. 불필요한 추가 공간이 없다.
개선 제안: 현재 구현이 적절해 보입니다.
💡 풀이에 시간/공간 복잡도를 주석으로 남겨보세요!
There was a problem hiding this comment.
🏷️ 알고리즘 패턴 분석
set-matrix-zeroes/dolphinflow86.py
# R is the number of rows, and C is the number of columns.
# TC: O(R * C) - scans each cell a constant number of times
# SC: O(1) - uses the first row and column as markers
class Solution:
def setZeroes(self, matrix: List[List[int]]) -> None:
row_count = len(matrix)
column_count = len(matrix[0])
first_row_has_zero = any(matrix[0][col] == 0 for col in range(column_count))
first_column_has_zero = any(matrix[row][0] == 0 for row in range(row_count))
for row in range(1, row_count):
for col in range(1, column_count):
if matrix[row][col] == 0:
matrix[row][0] = 0
matrix[0][col] = 0
for row in range(1, row_count):
for col in range(1, column_count):
if matrix[row][0] == 0 or matrix[0][col] == 0:
matrix[row][col] = 0
if first_row_has_zero:
for col in range(column_count):
matrix[0][col] = 0
if first_column_has_zero:
for row in range(row_count):
matrix[row][0] = 0- 패턴: Dynamic Programming, Greedy, Hash Map / Hash Set
- 설명: 해당 코드는 행렬의 특정 행/열 정보를 임시 마커로 사용해 추가 공간 없이 제로를 확산시키는 방식이다. 첫 행과 열을 마커로 활용하는 방식은 공간 최적화를 위한 아이디어로, DP의 부분 문제 관리나 배치 방식과 유사한 패턴으로 볼 수 있다.
📊 시간/공간 복잡도 분석
| 유저 분석 | 실제 분석 | 결과 | |
|---|---|---|---|
| Time | O(R * C) | O(R*C) | ✅ |
| Space | O(1) | O(1) | ✅ |
피드백: 추가 배열 없이 첫 행/열의 플래그를 재활용하는 공간 최적화 방식이다.
개선 제안: 현재 구현이 적절해 보입니다.
There was a problem hiding this comment.
🏷️ 알고리즘 패턴 분석
unique-paths/dolphinflow86.py
# M is the number of rows, and N is the number of columns.
# TC: O(M * N) - calculates the number of paths from each cell once
# SC: O(M * N) - uses a memo dictionary and the recursion stack
class Solution:
def dfs(self, row, col, m, n, memo):
if row == m - 1 and col == n - 1:
return 1
if row >= m or col >= n:
return 0
if (row, col) in memo:
return memo[(row, col)]
memo[(row, col)] = (
self.dfs(row + 1, col, m, n, memo)
+ self.dfs(row, col + 1, m, n, memo)
)
return memo[(row, col)]
def uniquePaths(self, m: int, n: int) -> int:
memo = {}
return self.dfs(0, 0, m, n, memo)- 패턴: Dynamic Programming, Depth-First Search, Memoization
- 설명: 초기 위치에서 오른쪽/아래로 가는 경로 합을 재귀적으로 구하고, 중복 계산을 메모이제이션으로 줄이는 방식으로 DP를 구현한 예로, DFS 탐색과 함께 결과를 저장하는 패턴이다.
📊 시간/공간 복잡도 분석
| 유저 분석 | 실제 분석 | 결과 | |
|---|---|---|---|
| Time | O(M * N) | O(m*n) | ✅ |
| Space | O(M * N) | O(m*n) | ✅ |
피드백: 하위 문제 재사용으로 중복을 제거하고, 최종적으로 모든 경로의 수를 합친다.
개선 제안: 현재 구현이 적절해 보입니다.
yuseok89
left a comment
There was a problem hiding this comment.
코멘트가 몇 개 있긴한데, 큰 부분은 아니라 approve 합니다.
코멘트는 시간 있을 때 여유롭게 봐주세요.
한 주 고생 많으셨습니다 👍 💯
| dfs(row - 1, col) | ||
| dfs(row + 1, col) | ||
| dfs(row, col - 1) | ||
| dfs(row, col + 1) |
There was a problem hiding this comment.
코드 자체는 깔끔해지는데, 사전에 체크해서 쌓지 않아도 될 call stack 이 쌓이는 부분은 있는 것 같습니다.
There was a problem hiding this comment.
재귀 DP + 메모이제이션으로 잘 구현해주신 것 같습니다.
| # SC: O(M * N) - uses a memo dictionary and the recursion stack | ||
| class Solution: | ||
|
|
||
| def dfs(self, row, col, m, n, memo): |
There was a problem hiding this comment.
dfs 함수를 uniquePaths 안에 구현하면, 인자 개수를 줄일 수 있을 것 같습니다.
답안 제출 문제
작성자 체크 리스트
In Review로 설정해주세요.검토자 체크 리스트
Important
본인 답안 제출 뿐만 아니라 다른 분 PR 하나 이상을 반드시 검토를 해주셔야 합니다!