-
-
Notifications
You must be signed in to change notification settings - Fork 362
[dolphinflow86] WEEK 04 Solutions #2741
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
Changes from all commits
7353b8a
d3c61fa
86f27d2
146a402
633a9e0
caeb4b5
39420d1
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,19 @@ | ||
| # 1) Use top-down memoization, recursively calculate the minimum coins required for each remaining amount and cache the results to prune duplicated branches. | ||
| # TC: O(K^M) where K is the number of coins, where M is the amount. We can recurse down at most M depth | ||
| # SC: O(K + M) | ||
| class Solution: | ||
| def dfs(self, coins: List[int], memo:Dict[int, int], remain: int): | ||
| if remain == 0: return 0 | ||
| if remain < 0: return float('inf') | ||
| if remain in memo: return memo[remain] | ||
|
|
||
| min_result = float('inf') | ||
| for coin in coins: | ||
| min_result = min(min_result, self.dfs(coins, memo, remain - coin)) | ||
|
|
||
| memo[remain] = min_result if min_result == float('inf') else min_result + 1 | ||
| return memo[remain] | ||
|
|
||
| def coinChange(self, coins: List[int], amount: int) -> int: | ||
| result = self.dfs(coins, {}, amount) | ||
| return result if result != float('inf') else -1 |
|
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. 혹시 pivot을 (right + left) // 2 가 아닌 left + (right - left) // 2 로 하신 이유가 있으실까요?
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,20 @@ | ||||||
| # 1) Use binary search to halves to search range. Each iteration, | ||||||
| # compare with nums[pivot] and nums[right] to see which side has a smaller range. | ||||||
| # Firstly I compare nums[left] with nums[right] so I got the wrong results but end up with the right solution. | ||||||
| # TC: O(logN) where N is the length of the nums array | ||||||
| # SC: O(1) | ||||||
|
|
||||||
| class Solution: | ||||||
| def findMin(self, nums: List[int]) -> int: | ||||||
| n = len(nums) | ||||||
| left = 0 | ||||||
| right = n-1 | ||||||
|
|
||||||
| while left < right: | ||||||
| mid = left + (right - left) // 2 | ||||||
| if nums[mid] < nums[right]: | ||||||
| right = mid | ||||||
| else: | ||||||
| left = mid + 1 | ||||||
|
|
||||||
| return nums[right] | ||||||
|
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. nit: right 보단 left가 약간 더 자연스러운(?) 개인적인 느낌이 있는 거 같습니다.
Suggested change
|
||||||
|
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. 이거 depth 패러미터 주지 않고 maxDepth 만으로도 구현 가능하세요! 스스로 재귀해서 하면 코드도 엄청 줄일수 있어요, 성능도 같고요
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. bottom up 방식으로 depth를 더하면서 올라오면 간단하게 끝나는군요
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,21 @@ | ||
| # 1) Use DFS to traverse down to the leaf node. Keep track of depth and return each node's maximum depth of each subtree to the parent node. | ||
| # TC: O(N) where N is the number of node in the binary tree | ||
| # SC: O(H) where H is the height of the binary tree | ||
| # 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 dfs(self, node: Optional[TreeNode], depth: int) -> int: | ||
| if not node: | ||
| return depth | ||
|
|
||
| return max( | ||
| self.dfs(node.left, depth + 1), | ||
| self.dfs(node.right, depth + 1) | ||
| ) | ||
|
|
||
| def maxDepth(self, root: Optional[TreeNode]) -> int: | ||
| return self.dfs(root, 0) |
|
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,27 @@ | ||
| # 1) Use a dummy node and connect the smaller node to the merged list while iterating through both lists. | ||
| # TC: O(N + M) where N is the length of list1 and M is the length of list2. | ||
| # SC: O(1) | ||
| # | ||
| # Definition for singly-linked list. | ||
| # class ListNode: | ||
| # def __init__(self, val=0, next=None): | ||
| # self.val = val | ||
| # self.next = next | ||
|
|
||
| class Solution: | ||
| def mergeTwoLists(self, list1: Optional[ListNode], list2: Optional[ListNode]) -> Optional[ListNode]: | ||
| dummy = ListNode() | ||
| curr = dummy | ||
|
|
||
| while list1 and list2: | ||
| if list1.val < list2.val: | ||
| curr.next = list1 | ||
| list1 = list1.next | ||
| else: | ||
| curr.next = list2 | ||
| list2 = list2.next | ||
| curr = curr.next | ||
|
|
||
| curr.next = list1 if list1 else list2 | ||
|
|
||
| return dummy.next | ||
|
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. dummy 도 괜찮은데 의미를 조금 더 담은 네이밍이면 어떨까 싶습니다. |
||
|
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. 실제로 돌려보니 4000ms 정도 나오는데 조금 더 최적화 해보셔도 좋을 것 같습니다.
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,42 @@ | ||
| # 1) Use dfs and backtracking to search for a word in the board. | ||
| # TC: O(N*M*3^W) where N is len(row), M is len(col) and W is len(word) | ||
| # SC: O(N*M) representing the maximum depth of the recursion tack. | ||
| class Solution: | ||
| def dfs(self, board: List[List[str]], word: str, row: int, col: int, word_idx: int) -> bool: | ||
| if row < 0 or col < 0 or row >= len(board) or col >= len(board[0]): | ||
| return False | ||
|
|
||
| if word_idx >= len(word) or board[row][col] != word[word_idx]: | ||
| return False | ||
|
|
||
| if word_idx == len(word) - 1: | ||
| return True | ||
|
|
||
| temp = board[row][col] | ||
| board[row][col] = '#' | ||
|
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. 추가 공간 없이 임시문자로 대체 했다가 복구하는 것도 좋은 방법이네요 👍🏼 |
||
|
|
||
| found = ( | ||
| self.dfs(board, word, row + 1, col, word_idx + 1) or | ||
| self.dfs(board, word, row - 1, col, word_idx + 1) or | ||
| self.dfs(board, word, row, col + 1, word_idx + 1) or | ||
| self.dfs(board, word, row, col - 1, word_idx + 1) | ||
| ) | ||
|
|
||
| board[row][col] = temp | ||
|
|
||
| return found | ||
|
|
||
| def exist(self, board: List[List[str]], word: str) -> bool: | ||
| row_len = len(board) | ||
| column_len = len(board[0]) | ||
| word_len = len(word) | ||
|
|
||
| # Early return if the board contains fewer cells than the word length. | ||
| if row_len * column_len < word_len: return False | ||
|
|
||
| for i in range(row_len): | ||
| for j in range(column_len): | ||
| if self.dfs(board, word, i, j, 0): | ||
| return True | ||
|
|
||
| return False | ||
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.
🏷️ 알고리즘 패턴 분석
📊 시간/공간 복잡도 분석
피드백: 상향식이 아닌 탑다운 방식으로 중복 서브문제 계산을 줄인다. 그러나 최악의 경우 각 남은 금액에 대해 모든 동전을 시도하므로 O(amount * len(coins))의 시간복잡도가 된다.
개선 제안: 현재 구현이 적절해 보입니다.