Skip to content

Commit b279188

Browse files
authored
Merge pull request DaleStudy#821 from thispath98/main
[thispath98] Week 4
2 parents 96f9b46 + a30cffa commit b279188

File tree

5 files changed

+326
-0
lines changed

5 files changed

+326
-0
lines changed

coin-change/thispath98.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
class Solution:
2+
def coinChange(self, coins: List[int], amount: int) -> int:
3+
"""
4+
Intuition:
5+
dp 배열에 이전 금액에 대한 최소 개수를 저장해두고
6+
갱신하는 방식으로 작동한다.
7+
8+
for 루프를 돌면서 현재 가격에서 coin만큼의 가격을
9+
뺐을 때 거슬러줄 수 있다면, 그 값에서 1개를 더해준
10+
개수를 prev_coins에 저장한다.
11+
12+
이후 prev_coins가 존재하면 현재 인덱스에서 거슬러줄 수 있는
13+
동전의 최소 개수를 갱신한다.
14+
15+
Time Complexity:
16+
O(amount x coins.length):
17+
amount 만큼 루프를 순회하는데 각 루프마다
18+
coins.length 만큼 prev_coins 배열을 만든다.
19+
20+
Space Complexity:
21+
O(amount):
22+
amount만큼의 크기를 가지는 dp 배열을 저장한다.
23+
"""
24+
dp = [0 for _ in range(amount + 1)]
25+
26+
for coin in coins:
27+
if coin <= amount:
28+
dp[coin] = 1
29+
30+
for i in range(1, amount + 1):
31+
if dp[i]:
32+
continue
33+
34+
prev_coins = [dp[i - coin] + 1 for coin in coins if i >= coin and dp[i - coin] > 0]
35+
if prev_coins:
36+
dp[i] = min(prev_coins)
37+
38+
answer = -1 if amount > 0 and dp[amount] == 0 else dp[amount]
39+
return answer

merge-two-sorted-lists/thispath98.py

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
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+
class Solution:
7+
def mergeTwoListsList(self, list1: Optional[ListNode], list2: Optional[ListNode]) -> Optional[ListNode]:
8+
"""
9+
Intuition:
10+
두 리스트의 원소를 각각 비교하면서 한번씩 스캔한다.
11+
결과적으로 한번씩만 스캔하면 정렬할 수 있다.
12+
13+
Time Complexity:
14+
O(N):
15+
두개의 리스트를 1번 순회하며 답을 찾으므로,
16+
O(N)의 시간복잡도가 소요된다.
17+
18+
Space Complexity:
19+
O(N):
20+
sorted_list에 정렬된 배열을 저장하므로,
21+
O(N)의 공간복잡도가 소요된다.
22+
"""
23+
sorted_list = []
24+
while list1 is not None and list2 is not None:
25+
if list1.val < list2.val:
26+
sorted_list.append(list1.val)
27+
list1 = list1.next
28+
else:
29+
sorted_list.append(list2.val)
30+
list2 = list2.next
31+
32+
while list1 is not None:
33+
sorted_list.append(list1.val)
34+
list1 = list1.next
35+
while list2 is not None:
36+
sorted_list.append(list2.val)
37+
list2 = list2.next
38+
39+
sorted_node = None
40+
while sorted_list:
41+
val = sorted_list.pop()
42+
sorted_node = ListNode(val, sorted_node)
43+
44+
return sorted_node
45+
46+
def mergeTwoListsNode(self, list1: Optional[ListNode], list2: Optional[ListNode]) -> Optional[ListNode]:
47+
"""
48+
Intuition:
49+
파이썬 리스트를 사용하지 않고
50+
주어진 ListNode로부터 바로 시작한다.
51+
52+
Time Complexity:
53+
O(N):
54+
두개의 리스트를 1번 순회하며 답을 찾으므로,
55+
O(N)의 시간복잡도가 소요된다.
56+
57+
Space Complexity:
58+
O(1):
59+
ListNode를 바로 사용하므로
60+
상수 만큼의 O(1)의 공간복잡도가 소요된다.
61+
62+
Key takeaway:
63+
링크드 리스트를 오랜만에 접하니 잘 풀지 못했던 것 같다.
64+
전통적인 자료구조를 OOP 관점으로 고민해보자.
65+
"""
66+
sorted_node = ListNode()
67+
current_node = sorted_node
68+
69+
while True:
70+
if list1 is None:
71+
current_node.next = list2
72+
break
73+
elif list2 is None:
74+
current_node.next = list1
75+
break
76+
77+
if list1.val < list2.val:
78+
current_node.next = ListNode(list1.val)
79+
current_node = current_node.next
80+
list1 = list1.next
81+
else:
82+
current_node.next = ListNode(list2.val)
83+
current_node = current_node.next
84+
list2 = list2.next
85+
86+
return sorted_node.next

missing-number/thispath98.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
class Solution:
2+
def missingNumber(self, nums: List[int]) -> int:
3+
"""
4+
Intuition:
5+
주어진 리스트의 개수를 얻어 범위를 구한다.
6+
이후 세트를 이용해서 범위 내의 정수가
7+
세트 안에 없으면 그 수를 리턴한다.
8+
9+
Time Complexity:
10+
O(N):
11+
세트(해시)는 접근하는 데에 상수의 시간이 걸리므로
12+
최대 N + 1번의 접근을 하므로
13+
O(N)의 시간복잡도가 소요된다.
14+
15+
Space Complexity:
16+
O(N):
17+
리스트를 해시로 변환하여 저장하고 있으므로
18+
O(N)의 공간복잡도가 소요된다.
19+
"""
20+
num_set = set(nums)
21+
for i in range(len(nums) + 1):
22+
if i not in num_set:
23+
return i

palindromic-substrings/thispath98.py

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
class Solution:
2+
def countSubstrings(self, s: str) -> int:
3+
"""
4+
Intuition:
5+
2중 루프를 돌면서 각 substring에 대해
6+
palindrome인지 아닌지 확인한다.
7+
한번 palindrome인지 확인했으면, set에 추가하여
8+
중복 확인을 한다.
9+
10+
Time Complexity:
11+
O(N^2 x s.length):
12+
2중 루프는 N^2만큼 소요되고,
13+
각 루프에 palindrome을 체크하는 것은
14+
s.length만큼 소요된다.
15+
16+
Space Complexity:
17+
O(N^2):
18+
palindrome이 모두 중복되지 않을 경우 set에
19+
s의 substring 개수만큼 저장한다.
20+
이는 대략 N^2이다.
21+
"""
22+
def is_palindrome(s):
23+
return s == s[::-1]
24+
25+
palindrome_set = set()
26+
answer = 0
27+
for i in range(1, len(s) + 1):
28+
for j in range(0, len(s) - i + 1):
29+
substr = s[j: j + i]
30+
if substr in palindrome_set or is_palindrome(substr):
31+
palindrome_set.add(substr)
32+
answer += 1
33+
return answer
34+
35+
36+
class SolutionDPSet:
37+
def countSubstrings(self, s: str) -> int:
38+
"""
39+
Intuition:
40+
위 solution에서 중복을 제거할 수 있는 방법은,
41+
start : end 길이를 갖는 substring에서
42+
s[start] == s[end]이고, start + 1 : end - 1의
43+
substring이 palindrome이라면, 이 substring은
44+
palindrome이라고 볼 수 있다.
45+
46+
Time Complexity:
47+
O(N^2):
48+
DP로 인해 palindrome을 찾는 함수가 대략
49+
상수의 시간복잡도가 걸린다고 볼 수 있다.
50+
따라서 substring을 만드는 이중 루프에서의
51+
시간복잡도가 걸릴 수 있다고 보면 된다.
52+
53+
Space Complexity:
54+
O(N^2):
55+
dp set에 index set을 저장하는데, 최악의 경우
56+
index set은 N^2개만큼 저장될 수 있다.
57+
58+
Key takeaway:
59+
dp를 이용해서 푸는 방식에 대해 익숙해져야겠다.
60+
61+
의문점은 leetcode에서 bruteforce보다 시간이 더 소요되었다는 것이다.
62+
아마 list 크기를 초과할 경우에 append를 할 경우,
63+
리스트 크기를 2배만큼 늘리는 list doubling 방식이
64+
set에도 적용이 되어 느려진 것으로 보인다.
65+
"""
66+
dp = set()
67+
68+
69+
def is_palindrome(start, end):
70+
while start < end:
71+
if s[start] != s[end]:
72+
return False
73+
if (start, end) in dp:
74+
return True
75+
start += 1
76+
end -= 1
77+
78+
return True
79+
80+
81+
answer = 0
82+
for length in range(1, len(s) + 1):
83+
for start in range(0, len(s) - length + 1):
84+
end = start + length - 1
85+
if (start, end) in dp or is_palindrome(start, end):
86+
dp.add((start, end))
87+
answer += 1
88+
return answer
89+
90+
91+
class SolutionDPList:
92+
def countSubstrings(self, s: str) -> int:
93+
"""
94+
Intuition:
95+
DP solution에서 set로 저장하지 않고,
96+
이중 리스트로 저장하는 것으로 수정했다.
97+
length = 2인 경우에는 start와 end만 동일하면
98+
palindrome으로 판단할 수 있어 조건을 추가했다.
99+
100+
Time Complexity:
101+
O(N^2):
102+
DP로 인해 palindrome을 찾는 함수가 대략
103+
상수의 시간복잡도가 걸린다고 볼 수 있다.
104+
따라서 substring을 만드는 이중 루프에서의
105+
시간복잡도가 걸릴 수 있다고 보면 된다.
106+
107+
Space Complexity:
108+
O(N^2):
109+
dp 리스트에 substring 이중 리스트를 저장하므로
110+
N^2개만큼 저장될 수 있다.
111+
112+
Key takeaway:
113+
이 방법이 가장 빠르게 동작했다.
114+
"""
115+
dp = [[False for _ in s] for _ in s]
116+
answer = 0
117+
118+
for i in range(len(s)):
119+
dp[i][i] = True
120+
answer += 1
121+
122+
for length in range(2, len(s) + 1):
123+
for start in range(len(s) - length + 1):
124+
end = start + length - 1
125+
if s[start] == s[end]:
126+
if length == 2 or dp[start + 1][end - 1]:
127+
dp[start][end] = True
128+
answer += 1
129+
130+
return answer

word-search/thispath98.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
class Solution:
2+
def exist(self, board: List[List[str]], word: str) -> bool:
3+
"""
4+
Intuition:
5+
보드를 돌면서 dfs를 수행한다.
6+
dfs는 상하좌우를 돌면서 word의 index와
7+
board의 word가 동일한지 확인한다.
8+
9+
Time Complexity:
10+
O(M x N + w.length^4):
11+
M x N 크기의 배열을 돌면서,
12+
각 칸마다 상하좌우 4번씩 확인한다.
13+
최대 word length번만큼 반복한다.
14+
15+
Space Complexity:
16+
O(M x N + w.length):
17+
M x N 크기의 visited 배열을 초기화하고,
18+
dfs의 호출 스택은 word length만큼 반복한다.
19+
"""
20+
visited = [[False for _ in board[0]] for _ in board]
21+
22+
def dfs(y, x, index):
23+
if index == len(word):
24+
return True
25+
if not (0 <= y < len(board) and 0 <= x < len(board[0])):
26+
return False
27+
if visited[y][x]:
28+
return False
29+
if word[index] != board[y][x]:
30+
return False
31+
32+
visited[y][x] = True
33+
for dy, dx in [[-1, 0], [1, 0], [0, -1], [0, 1]]:
34+
ny = y + dy
35+
nx = x + dx
36+
37+
if dfs(ny, nx, index + 1):
38+
return True
39+
40+
visited[y][x] = False
41+
return False
42+
43+
for i in range(len(board)):
44+
for j in range(len(board[0])):
45+
if dfs(i, j, 0):
46+
return True
47+
48+
return False

0 commit comments

Comments
 (0)