-
-
Notifications
You must be signed in to change notification settings - Fork 362
[alphaorderly] WEEK 07 Solutions #2793
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
4d5f428
3ac63f5
2536209
612dbbb
a7c2098
79f6f86
3855235
33ab6bc
b1de0e1
f9bf16c
de3390f
b3dc7d7
17669b6
d8b5903
a14205b
b087a32
2380e81
e51ae37
9592367
555e26d
9b11b3c
aeffd8e
9fb334a
cad3e9b
5d805dd
d64aecd
f9db228
266bdae
bff71b4
4a6924f
054781c
4e6a737
df718e2
500a10e
85e0321
1d3d1e7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| """ | ||
| Time Complexity: O(n) | ||
| Space Complexity: O(n) | ||
|
|
||
| Approach: | ||
| - Use a defaultdict to track the count of each character in the current window. | ||
| - Maintain two pointers, 'left' and 'right', to represent the sliding window over the string. | ||
| - As we iterate over the string with 'right', increment the count for the current character. | ||
| - If a duplicate character appears in the window (count > 1), move the 'left' pointer forward and decrement counts until there are no duplicates. | ||
| - After adjusting, update 'ans' with the maximum length found for a window with all unique characters. | ||
| """ | ||
| class Solution: | ||
| def lengthOfLongestSubstring(self, s: str) -> int: | ||
| count = defaultdict(int) | ||
| ans = left = 0 | ||
|
|
||
| for right, val in enumerate(s): | ||
| count[val] += 1 | ||
|
|
||
| while count[val] > 1: | ||
| count[s[left]] -= 1 | ||
| left += 1 | ||
|
|
||
| ans = max(ans, right - left + 1) | ||
|
|
||
| return ans |
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🏷️ 알고리즘 패턴 분석
📊 시간/공간 복잡도 분석
풀이 1:
|
| 복잡도 | |
|---|---|
| Time | O(m * n) |
| Space | O(m * n) |
피드백: 두 가지 구현이 제시되어 있으며 모두 탐색으로 모든 육지('1')를 방문한다. 방문 여부를 표시하기 위해 grid를 변형하여 추가 공간을 사용하지 않는다.
개선 제안: 현재 구현이 적절해 보입니다.
풀이 2: Solution.numIslands — Time: O(m * n) / Space: O(m * n)
| 복잡도 | |
|---|---|
| Time | O(m * n) |
| Space | O(m * n) |
피드백: 재귀를 이용한 DFS로 모든 연결된 육지를 탐색한다. 스택을 사용하는 구현과 동일한 시간/공간 복잡도다.
개선 제안: 현재 구현이 적절해 보입니다.
💡 풀이에 시간/공간 복잡도를 주석으로 남겨보세요!
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,87 @@ | ||
| """ | ||
| Time Complexity: O(m * n) | ||
| Space Complexity: O(m * n) | ||
|
|
||
| ### BFS Approach ### | ||
|
|
||
| Approach: | ||
| - Use BFS to traverse all parts of each island in the grid. | ||
| - Employ a queue to process all adjacent land cells iteratively. | ||
| - Use a 'bound' helper function to check if a cell is within the grid bounds. | ||
| - In 'island_marker', mark visited '1's with '#' to avoid revisiting. | ||
| - For every cell in the grid, when a land cell ('1') is encountered, initiate BFS and increment the island count. | ||
| """ | ||
| class Solution: | ||
| def numIslands(self, grid: List[List[str]]) -> int: | ||
| DIR = [[0, 1], [1, 0], [-1, 0], [0, -1]] | ||
| ROW = len(grid) | ||
| COL = len(grid[0]) | ||
|
|
||
| def bound(row: int, col: int) -> bool: | ||
| return 0 <= row < ROW and 0 <= col < COL | ||
|
|
||
| def island_marker(row: int, col: int) -> None: | ||
| q = deque([(row, col)]) | ||
| grid[row][col] = "#" | ||
|
|
||
| while q: | ||
| r, c = q.popleft() | ||
|
|
||
| for dr, dc in DIR: | ||
| tr, tc = r + dr, c + dc | ||
|
|
||
| if not bound(tr, tc) or grid[tr][tc] != "1": | ||
| continue | ||
|
|
||
| grid[tr][tc] = "#" | ||
| q.append((tr, tc)) | ||
|
|
||
| ans = 0 | ||
|
|
||
| for r in range(ROW): | ||
| for c in range(COL): | ||
| if grid[r][c] == "1": | ||
| island_marker(r, c) | ||
| ans += 1 | ||
|
|
||
| return ans | ||
|
|
||
| """ | ||
| Time Complexity: O(m * n) | ||
| Space Complexity: O(m * n) | ||
|
|
||
| ### DFS Approach ### | ||
|
|
||
| Approach: | ||
| - Use DFS to traverse all parts of each island in the grid. | ||
| - Visitation is done recursively rather than with a stack, so stack comment is removed for clarity. | ||
| - Use a 'bound' helper function to check if a cell is within the grid bounds. | ||
| - In 'island_marker', mark visited '1's with '#' to avoid revisiting. | ||
| - For every cell in the grid, when a land cell ('1') is encountered, initiate DFS and increment the island count. | ||
| """ | ||
| class Solution: | ||
| def numIslands(self, grid: List[List[str]]) -> int: | ||
| DIR = [[0, 1], [1, 0], [-1, 0], [0, -1]] | ||
| ROW = len(grid) | ||
| COL = len(grid[0]) | ||
|
|
||
| def bound(row: int, col: int) -> bool: | ||
| return 0 <= row < ROW and 0 <= col < COL | ||
|
|
||
| def island_marker(row: int, col: int) -> None: | ||
| grid[row][col] = '#' | ||
|
|
||
| for dr, dc in DIR: | ||
| tr, tc = row + dr, col + dc | ||
| if bound(tr, tc) and grid[tr][tc] == '1': | ||
| island_marker(tr, tc) | ||
|
|
||
| ans = 0 | ||
|
|
||
| for r in range(ROW): | ||
| for c in range(COL): | ||
| if grid[r][c] == "1": | ||
| island_marker(r, c) | ||
| ans += 1 | ||
|
|
||
| return ans |
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🏷️ 알고리즘 패턴 분석
📊 시간/공간 복잡도 분석
피드백: 단일 포인터를 활용해 앞 노드와 현재 노드의 연결을 역전한다. 개선 제안: 현재 구현이 적절해 보입니다.
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| """ | ||
| Time Complexity: O(n) | ||
| Space Complexity: O(1) | ||
|
|
||
| - We use a while loop to traverse the linked list. | ||
| - We use a prev pointer to store the previous node. | ||
| - We use a head pointer to store the current node. | ||
| - We use a old_next pointer to store the next node. | ||
| - We use a prev, head = head, old_next to update the prev and head pointers. | ||
| - We return the prev pointer. | ||
| """ | ||
|
|
||
| class ListNode: | ||
| def __init__(self, val=0, next=None): | ||
| self.val = val | ||
| self.next = next | ||
|
|
||
| class Solution: | ||
| def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]: | ||
| prev = None | ||
|
|
||
| while head: | ||
| prev, head.next, head = head, prev, head.next | ||
|
|
||
| return prev |
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🏷️ 알고리즘 패턴 분석
📊 시간/공간 복잡도 분석
피드백: 첫 행/열을 마커로 활용하는 표준 최적화 방법을 택했다. 초기 상태를 따로 확인하여 경계 케이스를 처리한다. 개선 제안: 현재 구현이 적절해 보입니다.
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| """ | ||
| Time Complexity: O(m * n) | ||
| Space Complexity: O(1) | ||
|
|
||
| Approach: | ||
| - Use the first row and first column as markers to track which rows and columns should be zeroed. | ||
| - First, check if the original first row or first column should be zeroed by scanning them separately. | ||
| - Then, scan the rest of the matrix. If an element is zero, set its corresponding first row and first column positions to zero. | ||
| - Next, iterate through the matrix (excluding the first row and column) and set elements to zero if their corresponding first row or first column are zero. | ||
| - Finally, zero the first row and/or first column if initially flagged. | ||
| """ | ||
| class Solution: | ||
| def setZeroes(self, matrix: List[List[int]]) -> None: | ||
| ROW = len(matrix) | ||
| COL = len(matrix[0]) | ||
|
|
||
| row_check = any(matrix[0][c] == 0 for c in range(COL)) | ||
| col_check = any(matrix[r][0] == 0 for r in range(ROW)) | ||
|
|
||
| for r in range(ROW): | ||
| for c in range(COL): | ||
| if matrix[r][c] == 0: | ||
| matrix[r][0] = 0 | ||
| matrix[0][c] = 0 | ||
|
|
||
| for r in range(1, ROW): | ||
| for c in range(1, COL): | ||
| if matrix[r][0] == 0 or matrix[0][c] == 0: | ||
| matrix[r][c] = 0 | ||
|
|
||
| if row_check: | ||
| for c in range(COL): | ||
| matrix[0][c] = 0 | ||
|
|
||
| if col_check: | ||
| for r in range(ROW): | ||
| matrix[r][0] = 0 |
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 2D DP에서 dp 내용을 출력하고
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🏷️ 알고리즘 패턴 분석
📊 시간/공간 복잡도 분석
풀이 1:
|
| 복잡도 | |
|---|---|
| Time | O(m * n) |
| Space | O(m * n) |
피드백: 여러 접근 방식이 포함되어 있지만 각각의 구현은 서로 다른 공간/시간 특성을 가진다. 문제에 따라 선택적으로 사용할 수 있다.
개선 제안: 현재 구현이 적절해 보입니다.
풀이 2: Solution.uniquePaths — Time: O(m * n) / Space: O(n)
| 복잡도 | |
|---|---|
| Time | O(m * n) |
| Space | O(n) |
피드백: 행마다 열의 경로를 누적 업데이트하여 공간을 줄인다.
개선 제안: 현재 구현이 적절해 보입니다.
풀이 3: Solution.uniquePaths — Time: O(1) / Space: O(1)
| 복잡도 | |
|---|---|
| Time | O(1) |
| Space | O(1) |
피드백: 팩토리얼 기반의 조합 계산으로 시간 복잡도는 입력에 따라 달라지지만 일반적으로 상수 계수의 차이가 있다.
개선 제안: 현재 구현이 적절해 보입니다.
풀이 4: Solution.uniquePaths — Time: O(m * n) / Space: O(m * n)
| 복잡도 | |
|---|---|
| Time | O(m * n) |
| Space | O(m * n) |
피드백: 재귀 기반의 방법으로 중복되는 부분 문제를 저장해 효율을 유지한다.
개선 제안: 현재 구현이 적절해 보입니다.
💡 풀이에 시간/공간 복잡도를 주석으로 남겨보세요!
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,74 @@ | ||
| """ | ||
| Time Complexity: O(m * n) | ||
| Space Complexity: O(m * n) | ||
|
|
||
| Dynamic Programming (2D DP approach): | ||
| - Use a 2D array where maze[i][j] represents the number of unique paths to cell (i, j). | ||
| - Initialize the first row and first column with 1 (since there's only one way to reach each cell: only right moves for the first row or only down moves for the first column). | ||
| - For all other cells, maze[i][j] = maze[i-1][j] + maze[i][j-1] (sum of paths from the cell above and the cell to the left). | ||
| - Return maze[m-1][n-1] as the answer, which is the total number of unique paths. | ||
| """ | ||
| class Solution: | ||
| def uniquePaths(self, m: int, n: int) -> int: | ||
| maze = [[1] * n for _ in range(m)] | ||
|
|
||
| for i in range(1, m): | ||
| for j in range(1, n): | ||
| maze[i][j] = maze[i - 1][j] + maze[i][j - 1] | ||
|
|
||
| return maze[m - 1][n - 1] | ||
|
|
||
| """ | ||
| Time Complexity: O(m * n) | ||
| Space Complexity: O(n) | ||
|
|
||
| Dynamic Programming (1D DP optimization): | ||
| - Use a 1D array dp of size n. | ||
| - dp[c] keeps track of the number of unique paths to column c in the current row. | ||
| - Initialize dp with 1s (the first row has only one way to reach each column). | ||
| - For every row from the second onward, update dp[c] = dp[c] + dp[c - 1] (add ways from the left neighbor to ways accumulated so far). | ||
| - Return dp[-1] as the answer, representing the number of unique paths to the bottom-right cell. | ||
| """ | ||
| class Solution: | ||
| def uniquePaths(self, m: int, n: int) -> int: | ||
| dp = [1] * n | ||
|
|
||
| for _ in range(m - 1): | ||
| for c in range(1, n): | ||
| dp[c] += dp[c - 1] | ||
|
|
||
| return dp[-1] | ||
|
|
||
| """ | ||
| Time Complexity: O(m + n) | ||
| Space Complexity: O(1) | ||
|
|
||
| Combinatorial approach: | ||
| - The problem reduces to choosing (m-1) moves down from (m+n-2) total movements (or equivalently (n-1) moves right). | ||
| - The number of unique paths is given by the formula (m+n-2)! / [(m-1)! * (n-1)!], representing all possible orderings of down and right moves. | ||
| - Use the combinatorial (factorial) formula to compute the result efficiently. | ||
| """ | ||
| class Solution: | ||
| def uniquePaths(self, m: int, n: int) -> int: | ||
| return comb(m + n - 2, n - 1) | ||
|
|
||
| """ | ||
| Time Complexity: O(m * n) | ||
| Space Complexity: O(m * n) | ||
|
|
||
| ### Top down dynamic programming (with memoization) ### | ||
|
|
||
| Approach: | ||
| - Use recursion with memoization (via functools.cache) to store the number of unique paths to (row, col). | ||
| - The recursive function dp(row, col) returns the number of unique paths from the top-left to (row, col). | ||
| - Base case: If row == 1 or col == 1, there's only one unique path. | ||
| - Otherwise, dp(row, col) = dp(row-1, col) + dp(row, col-1). | ||
| - The answer is dp(m, n), the number of unique paths to the bottom-right cell. | ||
| """ | ||
| class Solution: | ||
| @cache | ||
| def uniquePaths(self, m: int, n: int) -> int: | ||
| if m == 1 or n == 1: | ||
| return 1 | ||
|
|
||
| return self.uniquePaths(m - 1, n) + self.uniquePaths(m, n - 1) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🏷️ 알고리즘 패턴 분석
📊 시간/공간 복잡도 분석
피드백: 슬라이딩 윈도우와 해시맵(딕셔너리) 활용으로 각 문자 등장 여부를 관리한다. right 증가에 따라 중복이 생기면 left를 이동시키며 윈도우 크기를 조정한다.
개선 제안: 현재 구현이 적절해 보입니다.