Skip to content

Commit f35bdd7

Browse files
authored
Merge pull request #1421 from seungriyou/main
[seungriyou] Week 06 Solutions
2 parents c7c4ea6 + 8244215 commit f35bdd7

File tree

5 files changed

+255
-0
lines changed

5 files changed

+255
-0
lines changed
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# https://leetcode.com/problems/container-with-most-water/
2+
3+
from typing import List
4+
5+
class Solution:
6+
def maxArea(self, height: List[int]) -> int:
7+
"""
8+
[Complexity]
9+
- TC: O(n)
10+
- SC: O(1)
11+
12+
[Approach]
13+
양끝에서부터 범위를 좁히면서 확인하는 two-pointer를 이용한다.
14+
양끝 side 중 더 작은 쪽을 안쪽으로 한 칸 옮기면서 확인하고,
15+
만약 두 side가 길이가 같다면 두 개를 모두 안쪽으로 한 칸 옮긴다.
16+
"""
17+
18+
lo, hi = 0, len(height) - 1
19+
max_amount = 0
20+
21+
while lo < hi:
22+
# 양 끝 side 길이
23+
s1, s2 = height[lo], height[hi]
24+
25+
# max_amount 업데이트
26+
max_amount = max(max_amount, (hi - lo) * min(s1, s2))
27+
28+
# 더 낮은 side를 안쪽으로 한 칸 옮기기
29+
if s1 < s2:
30+
lo += 1
31+
elif s1 > s2:
32+
hi -= 1
33+
# 두 side의 크기가 같다면, 둘다 안쪽으로 한 칸씩 옮기기
34+
else:
35+
lo += 1
36+
hi -= 1
37+
38+
return max_amount
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
# https://leetcode.com/problems/design-add-and-search-words-data-structure/
2+
3+
from collections import defaultdict, deque
4+
5+
class TrieNode:
6+
def __init__(self):
7+
self.is_word = False
8+
self.children = defaultdict(TrieNode)
9+
10+
class WordDictionary:
11+
def __init__(self):
12+
self.root = TrieNode()
13+
14+
def addWord(self, word: str) -> None:
15+
curr = self.root
16+
17+
for w in word:
18+
curr = curr.children[w]
19+
20+
curr.is_word = True
21+
22+
def search(self, word: str) -> bool:
23+
"""
24+
BFS 혹은 DFS를 사용할 수 있다. 핵심은
25+
- "."을 마주치면 모든 children을 전부 타고 내려간다.
26+
- "."이 아닌 문자를 확인해야 한다면 해당 문자가 children에 있는지 확인 후 타고 내려간다.
27+
는 것이다.
28+
"""
29+
# return self._bfs(word)
30+
return self._dfs(self.root, word, 0)
31+
32+
def _dfs(self, curr, word, idx):
33+
# base condition
34+
if idx == len(word):
35+
return curr.is_word
36+
37+
# recur
38+
# (1) "."을 마주치면 모든 children에 대해 타고 내려간다.
39+
if word[idx] == ".":
40+
for child in curr.children.values():
41+
if self._dfs(child, word, idx + 1):
42+
return True
43+
44+
# (2) 현재 idx의 문자가 children에 있는지 확인 후에 타고 내려간다.
45+
if (w := word[idx]) in curr.children:
46+
return self._dfs(curr.children[w], word, idx + 1)
47+
48+
# (3) 그 외의 경우, False를 반환한다.
49+
return False
50+
51+
def _bfs(self, word):
52+
q = deque([(self.root, 0)]) # (node, idx)
53+
54+
while q:
55+
curr, idx = q.popleft()
56+
57+
# base condition
58+
if idx == len(word):
59+
if curr.is_word:
60+
return True
61+
62+
# iter
63+
# (1) "."을 마주치면 모든 children에 대해 타고 내려간다.
64+
elif word[idx] == ".":
65+
for child in curr.children.values():
66+
q.append((child, idx + 1))
67+
68+
# (2) 현재 idx의 문자가 children에 있는지 확인 후에 타고 내려간다.
69+
else:
70+
if (w := word[idx]) in curr.children:
71+
q.append((curr.children[w], idx + 1))
72+
73+
# (3) 그 외의 경우, False를 반환한다.
74+
return False
75+
76+
# Your WordDictionary object will be instantiated and called as such:
77+
# obj = WordDictionary()
78+
# obj.addWord(word)
79+
# param_2 = obj.search(word)
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# https://leetcode.com/problems/longest-increasing-subsequence/
2+
3+
from typing import List
4+
5+
class Solution:
6+
def lengthOfLIS_dp(self, nums: List[int]) -> int:
7+
"""
8+
[Complexity]
9+
- TC: O(n^2)
10+
- SC: O(n)
11+
12+
[Approach]
13+
dp[i] = nums[i]가 포함되는 LIS의 최대 길이
14+
"""
15+
n = len(nums)
16+
dp = [1] * n
17+
18+
for i in range(n):
19+
for j in range(i):
20+
if nums[j] < nums[i]:
21+
dp[i] = max(dp[i], dp[j] + 1)
22+
23+
return max(dp)
24+
25+
def lengthOfLIS(self, nums: List[int]) -> int:
26+
"""
27+
[Complexity]
28+
- TC: O(nlogn) (w. binary search)
29+
- SC: O(n)
30+
31+
[Approach]
32+
ref: https://leetcode.com/problems/longest-increasing-subsequence/solutions/1326308/c-python-dp-binary-search-bit-segment-tree-solutions-picture-explain-o-nlogn
33+
nums를 순차적으로 순회하며 LIS를 모은다. 이때,
34+
- 현재 보고 있는 원소 n이 LIS의 마지막 원소 이하라면: LIS의 원소 중 (1) n 이상이면서 (2) 최솟값의 위치에 n 덮어쓰기
35+
- 그 외의 경우라면: LIS의 맨 끝에 num append
36+
한다.
37+
LIS는 정렬되어 있을 것이므로 binary search를 이용할 수 있으며, 이렇게 구성한 LIS의 길이가 최대 길이이다.
38+
"""
39+
40+
def find_leftmost_idx(lis, n):
41+
lo, hi = 0, len(lis) - 1
42+
43+
while lo < hi:
44+
mid = lo + (hi - lo) // 2
45+
if lis[mid] < n: # -- 아예 제외하는 경우: n 미만인 경우
46+
lo = mid + 1
47+
else:
48+
hi = mid
49+
50+
return lo
51+
52+
lis = []
53+
54+
for n in nums:
55+
# 현재 보고 있는 n이 LIS의 마지막 원소 이하라면
56+
if lis and n <= lis[-1]:
57+
lis[find_leftmost_idx(lis, n)] = n
58+
# 그 외의 경우라면
59+
else:
60+
lis.append(n)
61+
62+
return len(lis)

spiral-matrix/seungriyou.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# https://leetcode.com/problems/spiral-matrix/
2+
3+
from typing import List
4+
5+
class Solution:
6+
def spiralOrder(self, matrix: List[List[int]]) -> List[int]:
7+
"""
8+
[Complexity]
9+
- TC: O(m * n) (m = row, n = col)
10+
- SC: O(1) (결과용 배열 res 제외)
11+
12+
[Approach]
13+
시계 방향으로 순회하도록, 방문 표시 & 방향 전환을 하면서 res에 값을 저장한다.
14+
이때, 방문 표시를 inplace로 한다면 추가 공간을 사용하지 않을 수 있다.
15+
"""
16+
17+
# 방향: 우 -> 하 -> 좌 -> 상
18+
dr, dc = [0, 1, 0, -1], [1, 0, -1, 0]
19+
row, col = len(matrix), len(matrix[0])
20+
21+
r, c, d = 0, 0, 0
22+
res = [matrix[r][c]]
23+
matrix[r][c] = "."
24+
25+
while len(res) < row * col:
26+
# 다음 위치 후보 구하기
27+
nr, nc = r + dr[d], c + dc[d]
28+
29+
# 다음 위치 후보가 (1) 범위를 벗어났거나 (2) 이미 방문한 위치라면, 방향 틀기
30+
if not (0 <= nr < row and 0 <= nc < col) or matrix[nr][nc] == ".":
31+
d = (d + 1) % 4
32+
nr, nc = r + dr[d], c + dc[d]
33+
34+
# res에 추가 & 방문 표시
35+
res.append(matrix[nr][nc])
36+
matrix[nr][nc] = "."
37+
38+
# 이동
39+
r, c = nr, nc
40+
41+
return res

valid-parentheses/seungriyou.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# https://leetcode.com/problems/valid-parentheses/
2+
3+
class Solution:
4+
def isValid(self, s: str) -> bool:
5+
"""
6+
[Complexity]
7+
- TC: O(n)
8+
- SC: O(n)
9+
10+
[Approach]
11+
s를 순회하면서 다음을 stack에 수행한다.
12+
- 닫는 괄호: stack이 비어있거나, stack.top이 매칭이 안 된다면 빠르게 False 반환 (+ 매칭이 된다면 stack.pop())
13+
- 여는 괄호: stack에 추가
14+
이렇게 전체를 순회했을 때 stack이 비어있어야 valid parentheses이다.
15+
"""
16+
17+
matches = {
18+
")": "(",
19+
"}": "{",
20+
"]": "["
21+
}
22+
23+
stack = []
24+
25+
for p in s:
26+
# 닫는 괄호: (1) stack이 비어있거나 (2) stack의 top이 pair가 아니라면 False (+ pair라면 stack.pop())
27+
if p in matches:
28+
if not stack or stack.pop() != matches[p]:
29+
return False
30+
# 여는 괄호: stack에 추가
31+
else:
32+
stack.append(p)
33+
34+
# stack이 비어있어야 valid parentheses
35+
return not stack

0 commit comments

Comments
 (0)