Skip to content

Commit aef74ca

Browse files
authored
Merge pull request DaleStudy#2477 from kangdaia/main
[kangdaia] WEEK 04 Solutions
2 parents 35eb79f + 267b872 commit aef74ca

7 files changed

Lines changed: 237 additions & 0 deletions

File tree

coin-change/kangdaia.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
class Solution:
2+
def coinChange(self, coins: list[int], amount: int) -> int:
3+
"""amount를 만들기 위해 최소한의 코인으로 구성할 수 있는 방안의 수를 구하는 함수
4+
동일한 동전을 여러번 사용해도 됨
5+
6+
방법:
7+
- 방법 수를 보고 dp로 풀기로 함. 금액이 dp 단계가 됨.
8+
모든 금액별로, 코인 목록을 돌면서, 코인을 사용할 수 있으면 amount-coin한 금액의 방법수 + 1과 비교하기
9+
-> 조합이 불가능한 상태를 어떻게 판단하지? 에서 dp init을 0이 아니라 inf로 해야, 구분이 가능하다는 점.
10+
-> 그래서 min 비교를 현재 인덱스 dp값과 i-coin의 dp 값 + 1으로 함
11+
coin이 정렬되지 않은 리스트라, 정렬해, coin 값이 amount를 넘어가면 pass
12+
13+
Args:
14+
coins (list[int]): 사용할 수 있는 동전 목록
15+
amount (int): 목표하는 금액
16+
17+
Returns:
18+
int: 금액을 만들기 위해 구성할 수 있는 동전들 방안 수
19+
"""
20+
dp = [float("inf")] * (amount + 1)
21+
dp[0] = 0
22+
coins.sort()
23+
for coin in coins:
24+
if coin > amount:
25+
continue
26+
for i in range(coin, amount + 1):
27+
dp[i] = min(dp[i], 1 + dp[i - coin])
28+
return dp[amount] if dp[amount] != float("inf") else -1

decode-ways/kangdaia.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
class Solution:
2+
def numDecodings(self, s: str) -> int:
3+
"""1에서 26까지 숫자를 알파벳으로 치환할 수 있을때,
4+
주어진 숫자 문자열이 어떤 알파벳으로 치환 될 수 있는지 방법의 수를 찾는 함수
5+
6+
방법:
7+
1. 경우의 수를 찾는 경우는 대부분 DP..?
8+
- 케이스가 명확함.
9+
현 위치의 숫자가 0이 아닌 경우, 해당 자리가 앞 숫자와 별개로 1~9 사이의 숫자를 선택할 수 있다.
10+
만약 앞의 경우를 포함해서 숫자가 10에서 26사이면 앞의 경우를 포함해서 경우의 숫자를 생각해야 함.
11+
다만 첫번째 숫자가 0이면 넘어가야 함.
12+
시간 복잡도: O(n) 공간 복잡도: O(n)
13+
14+
Args:
15+
s (str): 숫자로 이루어진 문자열
16+
17+
Returns:
18+
int: 문자열로 치환할 수 있는 알파벳 구성의 수
19+
"""
20+
dp = [0] * len(s)
21+
if s[0] != "0":
22+
dp[0] = 1
23+
for i in range(1, len(s)):
24+
if s[i] != "0":
25+
dp[i] += dp[i - 1]
26+
if "10" <= s[i - 1 : i + 1] <= "26":
27+
dp[i] += dp[i - 2] if i > 1 else 1
28+
return dp[-1]
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
class Solution:
2+
def findMin(self, nums: list[int]) -> int:
3+
"""
4+
정렬된 리스트에서 n번 돌아간 상태에서 기존의 첫번째 값 (가장 작은)을 찾는 함수
5+
6+
방법:
7+
Hint2의 Can you think of an algorithm which has O(logN) search complexity?
8+
에서 binary search!
9+
10+
Args:
11+
nums (list[int]): n번 돌아간 정수 리스트
12+
13+
Returns:
14+
int: 최초 정렬된 리스트의 첫번째 값
15+
"""
16+
if nums[0] <= nums[-1]:
17+
return nums[0]
18+
start, end = 0, len(nums) - 1
19+
while start < end:
20+
if start == end:
21+
break
22+
mid = start + (end - start) // 2
23+
if nums[mid] > nums[end]:
24+
start = mid + 1
25+
else:
26+
end = mid
27+
return nums[start]
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Definition for a binary tree node.
2+
class TreeNode:
3+
def __init__(self, val=0, left=None, right=None):
4+
self.val = val
5+
self.left = left
6+
self.right = right
7+
8+
9+
class Solution:
10+
def maxDepth(self, root: TreeNode | None) -> int:
11+
"""주어진 binary tree의 최대 깊이를 찾는 함수
12+
13+
방법:
14+
1. 재귀함수를 생각함. 인자로 현재 head node와 현재의 depth를 받는 재귀함수를 만들어 재귀 반복
15+
2. 이 함수 자체가 재귀가 될 수 있다고 판단, 별도의 재귀함수를 삭제함.
16+
depth를 넘겨주지 않아도, 앞에 +1을 함으로써 depth가 계산됨.
17+
18+
Args:
19+
root (TreeNode | None): binary tree
20+
21+
Returns:
22+
int: 최대 깊이
23+
"""
24+
if root is None:
25+
return 0
26+
return 1 + max(self.maxDepth(root.left), self.maxDepth(root.right))

maximum-subarray/kangdaia.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
class Solution:
2+
def maxSubArray(self, nums: list[int]) -> int:
3+
"""리스트의 이어진 문자열로 구성된 subarray중 최대 합을 찾는 함수
4+
5+
방법:
6+
1. brute force. 다만 O(n)으로 만들 수 없어 탈락!
7+
2. 전역 최대합과 로컬 최대 합을 분리해서 생각하기.
8+
연속된 문자열이기 때문에, 현재 값이 이전의 합보다 크면 앞의 값을 버리는 방식
9+
=> 시간 복잡도 O(n), 공간 복잡도 O(1)
10+
3. divide and conquer (Follow up)
11+
12+
Args:
13+
nums (list[int]): 정수 문자열
14+
15+
Returns:
16+
int: 최대 합
17+
"""
18+
max_sum = nums[0]
19+
local_sum = nums[0]
20+
for i in range(1, len(nums)):
21+
if local_sum < 0 and local_sum < nums[i]:
22+
local_sum = nums[i]
23+
else:
24+
local_sum += nums[i]
25+
max_sum = max(max_sum, local_sum)
26+
return max_sum
27+
28+
def maxSubArraySubtle(self, nums: list[int]) -> int:
29+
def divConq(left: int, right: int) -> int:
30+
if left == right:
31+
return nums[left]
32+
mid = (left + right) // 2
33+
34+
left_max = divConq(left, mid)
35+
right_max = divConq(mid + 1, right)
36+
37+
curr_sum = 0
38+
left_suffix_max = -float("inf")
39+
for idx in range(mid, left - 1, -1):
40+
curr_sum += nums[idx]
41+
left_suffix_max = max(left_suffix_max, curr_sum)
42+
43+
curr_sum = 0
44+
right_prefix_max = -float("inf")
45+
for idx in range(mid + 1, right + 1, 1):
46+
curr_sum += nums[idx]
47+
right_prefix_max = max(right_prefix_max, curr_sum)
48+
49+
cross = left_suffix_max + right_prefix_max
50+
return max(left_max, right_max, cross)
51+
52+
return divConq(0, len(nums) - 1)

merge-two-sorted-lists/kangdaia.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# Definition for singly-linked list.
2+
class ListNode:
3+
def __init__(self, val=0, next=None):
4+
self.val = val
5+
self.next = next
6+
7+
8+
class Solution:
9+
def mergeTwoLists(self, list1: ListNode | None, list2: ListNode | None) -> ListNode | None:
10+
"""두개의 링크드 리스트를 합쳐서 하나의 sorted 링크드 리스트를 만드는 함수
11+
12+
방법:
13+
1. 각각의 리스트 head에서 값을 비교하면서,
14+
1번보다 2번의 값이 작으면 1번의 head를 움직이고,
15+
반대의 경우 2번의 head를 움직이도록 함.
16+
움직이면서 합치는 리스트에 tail.next로 붙여줌
17+
18+
Args:
19+
list1 (ListNode | None): 정렬된 양수 링크드 리스트
20+
list2 (ListNode | None): 정렬된 양수 링크드 리스트 2
21+
22+
Returns:
23+
ListNode | None: 하나로 합쳐진 정렬된 링크드 리스트
24+
"""
25+
final = ListNode()
26+
tail = final
27+
curr1, curr2 = list1, list2
28+
while curr1 and curr2:
29+
if curr1.val < curr2.val:
30+
tail.next = curr1
31+
curr1 = curr1.next
32+
else:
33+
tail.next = curr2
34+
curr2 = curr2.next
35+
tail = tail.next
36+
tail.next = curr1 if curr1 else curr2
37+
return final.next

word-search/kangdaia.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
class Solution:
2+
def exist(self, board: list[list[str]], word: str) -> bool:
3+
"""m*n 사이즈 보드가 주어졌을 때, word를 만들 수 있는지 true/false로 return 하는 함수
4+
5+
1. bfs로 queue에 모든 element를 추가하고, 매번 path를 파악해서 word인지 판단하도록 함
6+
-> 시간 효율이 안나옴
7+
2. dfs 방식 적용. 현재 탐색 중일때, 보드를 #으로 치환해서, 이미 방문한 곳임을 체크
8+
- 시작점이 word[0]와 같을 때만 시작
9+
- dfs는 전체 path를 기록하지 않고, word가 볼 index를 인자로 받도록 함.
10+
11+
Args:
12+
board (list[list[str]]): 글자를 element로 가진 2d array
13+
word (str): 찾아야 할 글자 목록
14+
15+
Returns:
16+
bool: word가 board에 있는지 여부
17+
"""
18+
m, n = len(board[0]), len(board)
19+
20+
def dfs(row, col, idx):
21+
if board[row][col] != word[idx]:
22+
return False
23+
if idx == len(word) - 1:
24+
return True
25+
visited = board[row][col]
26+
board[row][col] = "#"
27+
for r, c in [(row - 1, col), (row + 1, col), (row, col - 1), (row, col + 1)]:
28+
if 0 <= r < n and 0 <= c < m:
29+
if dfs(r, c, idx + 1):
30+
board[row][col] = visited
31+
return True
32+
board[row][col] = visited
33+
return False
34+
35+
for ir in range(n):
36+
for ic in range(m):
37+
if board[ir][ic] == word[0] and dfs(ir, ic, 0):
38+
return True
39+
return False

0 commit comments

Comments
 (0)