-
-
Notifications
You must be signed in to change notification settings - Fork 304
[unpo88] WEEK 04 solutions #2123
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
Open
unpo88
wants to merge
6
commits into
DaleStudy:main
Choose a base branch
from
unpo88:main
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+338
−0
Open
Changes from 5 commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
d8243fe
feat: merge-two-sorted-lists 풀이 추가
unpo88 8e26447
feat: maximum-depth-of-binary-tree 풀이 추가
unpo88 65f2241
feat: find-minimum-in-rotated-sorted-array 풀이 추가
unpo88 645330b
feat: word-search 풀이 추가
unpo88 d6de949
feat: coin-change 풀이 추가
unpo88 11f97b1
Update coin-change/unpo88.py
unpo88 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,82 @@ | ||
| class Solution: | ||
| def coinChange(self, coins: list[int], amount: int) -> int: | ||
| dp = [float('inf')] * (amount + 1) | ||
| dp[0] = 0 | ||
|
|
||
| for coin in coins: | ||
| for x in range(coin, amount + 1): | ||
| dp[x] = min(dp[x], dp[x - coin] + 1) | ||
|
|
||
| return dp[amount] if dp[amount] != float('inf') else -1 | ||
|
|
||
| """ | ||
| ================================================================================ | ||
| 풀이 과정 | ||
| ================================================================================ | ||
|
|
||
| [1차 시도] 완전 탐색으로 접근하면? | ||
| ──────────────────────────────────────────────────────────────────────────────── | ||
| 1. 모든 동전 조합을 시도해보면 어떨까? | ||
| 2. coins = [1, 2, 5], amount = 11 | ||
| - 5 + 5 + 1 = 11 (3개) | ||
| - 5 + 2 + 2 + 2 = 11 (4개) | ||
| - 1 + 1 + ... (11개) | ||
| ... 너무 많은 경우의 수! | ||
|
|
||
| 3. 문제: 시간복잡도가 너무 높음 (지수 시간) | ||
| 4. 더 효율적인 방법이 필요함 → DP로 접근하자! | ||
|
|
||
| ──────────────────────────────────────────────────────────────────────────────── | ||
| [2차 시도] DP 초기화와 점화식 | ||
| ──────────────────────────────────────────────────────────────────────────────── | ||
| 5. dp[i] = i원을 만드는데 필요한 최소 동전 개수 | ||
| 6. 초기화: | ||
| - dp[0] = 0 (0원 만들기 = 동전 0개) | ||
| - dp[1~amount] = 아직 계산 안 됨 | ||
|
|
||
| dp = [float('inf')] * (amount + 1) | ||
| dp[0] = 0 | ||
|
|
||
| 7. 점화식: | ||
| - 각 동전 coin에 대해 | ||
| - dp[x] = min(dp[x], dp[x - coin] + 1) | ||
| - 의미: "x원 = (x-coin)원 + coin 1개" | ||
|
|
||
| 8. Eample) coins = [1, 2, 5], amount = 11 | ||
|
|
||
| 초기: dp = [0, inf, inf, inf, ..., inf] | ||
|
|
||
| 동전 1 처리: | ||
| dp[1] = min(inf, dp[0]+1) = 1 | ||
| dp[2] = min(inf, dp[1]+1) = 2 | ||
| dp[3] = min(inf, dp[2]+1) = 3 | ||
| ... | ||
|
|
||
| 동전 2 처리: | ||
| dp[2] = min(2, dp[0]+1) = 1 # 2원 동전 1개! | ||
| dp[3] = min(3, dp[1]+1) = 2 # 2+1 | ||
| dp[4] = min(4, dp[2]+1) = 2 # 2+2 | ||
| ... | ||
|
|
||
| 동전 5 처리: | ||
| dp[5] = min(5, dp[0]+1) = 1 # 5원 동전 1개! | ||
| dp[6] = min(6, dp[1]+1) = 2 # 5+1 | ||
| dp[10] = min(10, dp[5]+1) = 2 # 5+5 | ||
| dp[11] = min(11, dp[6]+1) = 3 # 5+5+1 | ||
|
|
||
|
|
||
| [최종 구현] Bottom-Up DP | ||
| ──────────────────────────────────────────────────────────────────────────────── | ||
| 12. 모든 동전에 대해 반복 | ||
| 13. 각 동전으로 만들 수 있는 모든 금액 업데이트 | ||
| 14. 불가능하면 -1 반환 (dp[amount]가 여전히 무한대) | ||
|
|
||
| for coin in coins: | ||
| for x in range(coin, amount + 1): | ||
| dp[x] = min(dp[x], dp[x - coin] + 1) | ||
|
|
||
| return dp[amount] if dp[amount] != float('inf') else -1 | ||
|
|
||
| 15. 시간복잡도: O(amount × coins) - 효율적! | ||
| 16. 공간복잡도: O(amount) - dp 배열 | ||
| """ | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| class Solution: | ||
| def findMin(self, nums: List[int]) -> int: | ||
| left, right = 0, len(nums) - 1 | ||
|
|
||
| while left < right: | ||
| mid = (left + right) // 2 | ||
|
|
||
| if nums[mid] > nums[right]: | ||
| left = mid + 1 | ||
| else: | ||
| right = mid | ||
|
|
||
| return nums[left] | ||
|
|
||
| """ | ||
| ================================================================================ | ||
| 풀이 과정 | ||
| ================================================================================ | ||
|
|
||
| [1차 시도] 이진 탐색 적용 - 기본 구조 | ||
| ──────────────────────────────────────────────────────────────────────────────── | ||
| 1. log(n) 시간 복잡도를 만족시키는 이진 탐색 구조로 최소값을 찾으면 될 것 같음 | ||
|
|
||
| left, right = 0, len(nums) - 1 | ||
|
|
||
| while left < right: | ||
| mid = (left + right) // 2 | ||
|
|
||
| if nums[mid] > nums[right]: | ||
| left = mid + 1 | ||
| else: | ||
| right = mid | ||
|
|
||
| return nums[left] | ||
|
|
||
| 2. 시간복잡도: O(log n) - 이진 탐색 | ||
| 3. 공간복잡도: O(1) - 추가 공간 사용 안 함 | ||
| """ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,52 @@ | ||
| # 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 maxDepth(self, root: Optional[TreeNode]) -> int: | ||
| if not root: | ||
| return 0 | ||
|
|
||
| left_depth = self.maxDepth(root.left) | ||
| right_depth = self.maxDepth(root.right) | ||
|
|
||
| return max(left_depth, right_depth) + 1 | ||
|
|
||
| """ | ||
| ================================================================================ | ||
| 풀이 과정 | ||
| ================================================================================ | ||
|
|
||
| [1차 시도] 재귀로 깊이 카운트 - None은 0 | ||
| ──────────────────────────────────────────────────────────────────────────────── | ||
| 1. 빈 노드(None)는 깊이가 0이 | ||
| 2. leaf 노드에서 양쪽 자식이 None이면 둘 다 0을 반환 | ||
| 3. 그러면 leaf 노드는 max(0, 0) + 1 = 1이 됨 (자기 자신만 카운트) | ||
|
|
||
| def maxDepth(self, root): | ||
| if not root: | ||
| return 0 # 빈 노드는 0 | ||
|
|
||
| left = self.maxDepth(root.left) | ||
| right = self.maxDepth(root.right) | ||
|
|
||
| return max(left, right) + 1 # 더 깊은 쪽 + 나 자신(1) | ||
|
|
||
| 4. 동작 예시: | ||
| 트리: 1 | ||
| / \ | ||
| 2 3 | ||
| / | ||
| 4 | ||
|
|
||
| maxDepth(4) → max(0, 0) + 1 = 1 | ||
| maxDepth(2) → max(1, 0) + 1 = 2 | ||
| maxDepth(3) → max(0, 0) + 1 = 1 | ||
| maxDepth(1) → max(2, 1) + 1 = 3 ✓ | ||
|
|
||
|
|
||
| 5. 시간복잡도: O(n) - 모든 노드를 1번씩 방문 | ||
| 6. 공간복잡도: O(h) - 재귀 스택, h는 트리 높이 | ||
| """ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,55 @@ | ||
| # 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() | ||
| head = dummy | ||
|
|
||
| while list1 and list2: | ||
| if list1.val < list2.val: | ||
| head.next = list1 | ||
| list1 = list1.next | ||
| else: | ||
| head.next = list2 | ||
| list2 = list2.next | ||
| head = head.next | ||
|
|
||
| if list1: | ||
| head.next = list1 | ||
| elif list2: | ||
| head.next = list2 | ||
|
|
||
| return dummy.next | ||
|
|
||
| """ | ||
| ================================================================================ | ||
| 풀이 과정 | ||
| ================================================================================ | ||
|
|
||
| [1차 시도] Dummy Node 활용 | ||
| ──────────────────────────────────────────────────────────────────────────────── | ||
| 1. 작은 값을 가진 노드를 골라서 head에 연결하는 방식으로 문제를 풀어보자. | ||
| 2. 한 쪽 리스트가 비게 되면 남은 노드를 그냥 연결해주면 될 것 같음. | ||
|
|
||
| dummy = ListNode() | ||
| head = dummy | ||
|
|
||
| while list1 and list2: | ||
| if list1.val < list2.val: | ||
| head.next = list1 | ||
| list1 = list1.next | ||
| else: | ||
| head.next = list2 | ||
| list2 = list2.next | ||
| head = head.next | ||
|
|
||
| if list1: | ||
| head.next = list1 | ||
| elif list2: | ||
| head.next = list2 | ||
|
|
||
| return dummy.next | ||
| """ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,111 @@ | ||
| class Solution: | ||
| def exist(self, board: list[list[str]], word: str) -> bool: | ||
| if not board or not board[0]: | ||
| return False | ||
|
|
||
| m, n = len(board), len(board[0]) | ||
|
|
||
| dx = [-1, 1, 0, 0] | ||
| dy = [0, 0, -1, 1] | ||
|
|
||
| def dfs(x, y, index): | ||
| if index == len(word): | ||
| return True | ||
|
|
||
| if x < 0 or x >= m or y < 0 or y >= n or board[x][y] != word[index]: | ||
| return False | ||
|
|
||
| temp = board[x][y] | ||
| board[x][y] = '#' | ||
|
|
||
| for i in range(4): | ||
| nx = x + dx[i] | ||
| ny = y + dy[i] | ||
| if dfs(nx, ny, index + 1): | ||
| return True | ||
|
|
||
| board[x][y] = temp | ||
| return False | ||
|
|
||
| for i in range(m): | ||
| for j in range(n): | ||
| if board[i][j] == word[0] and dfs(i, j, 0): | ||
| return True | ||
|
|
||
| return False | ||
|
|
||
| """ | ||
| ================================================================================ | ||
| 풀이 과정 | ||
| ================================================================================ | ||
|
|
||
| [1차 시도] DFS + 방향 배열로 접근 | ||
| ──────────────────────────────────────────────────────────────────────────────── | ||
| 1. 격자에서 상하좌우로 이동하며 단어를 찾아야 함 | ||
| 2. 같은 셀은 한 번만 사용 가능 → 방문 체크 필요 | ||
| 3. DFS(깊이 우선 탐색) + 백트래킹으로 풀면 될 것 같음 | ||
| 4. 상하좌우 이동을 위한 dx, dy 배열 만들자 | ||
|
|
||
| dx = [-1, 1, 0, 0] | ||
| dy = [0, 0, -1, 1] | ||
|
|
||
|
|
||
| [2차 시도] DFS 함수 구조 설계 | ||
| ──────────────────────────────────────────────────────────────────────────────── | ||
| 5. dfs(x, y, index) 형태로 현재 위치와 단어의 인덱스를 추적 | ||
| 6. base case: | ||
| - index == len(word): 단어 끝까지 찾음 → True | ||
| - 범위 벗어남 or 문자 불일치 → False | ||
|
|
||
| def dfs(x, y, index): | ||
| if index == len(word): | ||
| return True | ||
|
|
||
| if x < 0 or x >= m or y < 0 or y >= n or board[x][y] != word[index]: | ||
| return False | ||
|
|
||
| 7. 방문한 셀은 어떻게 표시하지? | ||
|
|
||
|
|
||
| [3차 시도] 방문 표시와 백트래킹 | ||
| ──────────────────────────────────────────────────────────────────────────────── | ||
| 8. 현재 셀을 '#' 같은 특수 문자로 임시 변경 (방문 표시) | ||
| 9. 4방향으로 재귀 탐색 | ||
| 10. 탐색 실패 시 원래 값으로 복원 (백트래킹) | ||
|
|
||
| temp = board[x][y] | ||
| board[x][y] = '#' | ||
|
|
||
| for i in range(4): | ||
| nx = x + dx[i] | ||
| ny = y + dy[i] | ||
| if dfs(nx, ny, index + 1): | ||
| return True | ||
|
|
||
| board[x][y] = temp | ||
| return False | ||
|
|
||
|
|
||
| [4차 시도] 조기 종료 최적화 추가 | ||
| ──────────────────────────────────────────────────────────────────────────────── | ||
| 11. 빈 보드는 바로 False 반환 | ||
| 12. 첫 글자가 일치하는 셀에서만 DFS 시작 (불필요한 탐색 방지) | ||
|
|
||
| if not board or not board[0]: | ||
| return False | ||
|
|
||
| for i in range(m): | ||
| for j in range(n): | ||
| if board[i][j] == word[0] and dfs(i, j, 0): | ||
| return True | ||
|
|
||
|
|
||
| [최종 구현] 최적화된 DFS 탐색 | ||
| ──────────────────────────────────────────────────────────────────────────────── | ||
| 13. 조기 종료로 불필요한 탐색 제거 | ||
| 14. 백트래킹으로 방문 상태 관리 | ||
| 15. 하나라도 성공하면 즉시 True 반환 | ||
|
|
||
| 16. 시간복잡도: O(m * n * 4^L) - 최악의 경우, 조기 종료로 실제로는 더 빠름 | ||
| 17. 공간복잡도: O(L) - 재귀 깊이 | ||
| """ |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.