Skip to content

Commit 48f60a2

Browse files
authored
Merge pull request #1214 from seungriyou/main
[seungriyou] Week 02 Solutions
2 parents c3118a9 + 2e6b9e1 commit 48f60a2

File tree

5 files changed

+277
-0
lines changed

5 files changed

+277
-0
lines changed

โ€Ž3sum/seungriyou.pyโ€Ž

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
# https://leetcode.com/problems/3sum/
2+
3+
from typing import List
4+
5+
6+
class Solution:
7+
def threeSum_slower(self, nums: List[int]) -> List[List[int]]:
8+
"""
9+
[Complexity]
10+
- TC: O(n^2)
11+
- SC: O(n)
12+
13+
[Approach]
14+
two sum ๋ฌธ์ œ์—์„œ ๊ณ ์ •๋œ ํ•˜๋‚˜์˜ ๊ฐ’๋งŒ ์ถ”๊ฐ€ํ•ด์„œ ํ’€ ์ˆ˜ ์žˆ๋‹ค.
15+
์ •๋ ฌ์„ ํ•œ ์ฐจ๋ก€ํ•˜๋ฉด, duplicated triplet ์ฒ˜๋ฆฌ๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค.
16+
"""
17+
18+
n = len(nums)
19+
nums.sort()
20+
21+
def two_sum(fixed_idx):
22+
remains = {}
23+
fixed_val = nums[fixed_idx]
24+
res = set()
25+
26+
for i in range(fixed_idx + 1, n):
27+
num = nums[i]
28+
if num in remains:
29+
res.add((nums[fixed_idx], nums[remains[num]], nums[i]))
30+
remains[-fixed_val - nums[i]] = i
31+
32+
return res
33+
34+
res = set()
35+
for i in range(n - 2):
36+
if ts := two_sum(i):
37+
res |= set(ts)
38+
39+
return [list(r) for r in res]
40+
41+
def threeSum(self, nums: List[int]) -> List[List[int]]:
42+
"""
43+
[Complexity]
44+
- TC: O(n^2)
45+
- SC: O(1) (res ์ œ์™ธํ•œ extra space)
46+
47+
[Approach]
48+
์ •๋ ฌ ํ›„, ํ•˜๋‚˜์˜ ๊ฐ’์„ ๊ณ ์ •ํ•ด๋‘๊ณ  two pointer๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ์‹์„ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.
49+
์ด๋•Œ ๋งค turn์—์„œ ์ค‘๋ณต ์›์†Œ๋ฅผ ๊ณ ๋ คํ•ด์„œ ๋ฏธ๋ฆฌ ์ด๋™ํ•˜๋ฉด duplicated triplet์„ ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ๋‹ค.
50+
"""
51+
52+
n = len(nums)
53+
res = []
54+
55+
# nums ์˜ค๋ฆ„์ฐจ์ˆœ ์ •๋ ฌ
56+
nums.sort()
57+
58+
for i in range(n - 2): # -- ํ•˜๋‚˜์˜ ๊ฐ’ ๊ณ ์ •
59+
# ๊ณ ์ •ํ•œ ๊ฐ’์ด ์ด์ „์— ๋‚˜์™”๋˜ ๊ฐ’์ด๋ฉด ๋น ๋ฅด๊ฒŒ ๋„˜์–ด๊ฐ€๊ธฐ
60+
if i > 0 and nums[i] == nums[i - 1]:
61+
continue
62+
63+
# ๊ณ ์ •๋œ ๊ฐ’๋ณด๋‹ค ํฐ ๊ฐ’ ๋ฒ”์œ„์—์„œ, ์–‘ ๋์—์„œ๋ถ€ํ„ฐ ์ขํ˜€์˜ค๋ฉฐ ํ™•์ธ
64+
j, k = i + 1, n - 1
65+
while j < k:
66+
_sum = nums[i] + nums[j] + nums[k]
67+
68+
# (1) _sum์ด 0๋ณด๋‹ค ํฌ๋ฉด k๋ฅผ ์™ผ์ชฝ์œผ๋กœ ํ•œ ์นธ ์ด๋™
69+
if _sum > 0:
70+
k -= 1
71+
# (2) _sum์ด 0๋ณด๋‹ค ์ž‘์œผ๋ฉด j๋ฅผ ์˜ค๋ฅธ์ชฝ์œผ๋กœ ํ•œ ์นธ ์ด๋™
72+
elif _sum < 0:
73+
j += 1
74+
# (3) _sum์ด 0์ด๋ผ๋ฉด res์— ์ถ”๊ฐ€
75+
else:
76+
triplet = [nums[i], nums[j], nums[k]]
77+
res.append(triplet)
78+
79+
# ์ค‘๋ณต ์›์†Œ ๊ฑด๋„ˆ๋›ฐ๊ธฐ (j๋Š” ์˜ค๋ฅธ์ชฝ์œผ๋กœ, k๋Š” ์™ผ์ชฝ์œผ๋กœ)
80+
while j < k and nums[j] == triplet[1]:
81+
j += 1
82+
while j < k and nums[k] == triplet[2]:
83+
k -= 1
84+
85+
return res
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# https://leetcode.com/problems/climbing-stairs/
2+
3+
class Solution:
4+
def climbStairs(self, n: int) -> int:
5+
"""
6+
[Complexity]
7+
- TC: O(n)
8+
- SC: O(1)
9+
10+
[Approach]
11+
dp[i] = i-th step์„ ์˜ค๋ฅผ ๋•Œ, ๊ฐ€๋Šฅํ•œ distinct ways์˜ ์ˆ˜
12+
= dp[i - 1] + dp[i - 2]
13+
์ด๋•Œ, dp[i - 1]๊ณผ dp[i - 2]๋งŒ ํ•„์š”ํ•˜๋ฏ€๋กœ, O(1) space๋กœ optimize ๊ฐ€๋Šฅํ•˜๋‹ค.
14+
prev1 = dp[i - 1]
15+
prev2 = dp[i - 2]
16+
์ฒซ ๋ฒˆ์งธ ๊ณ„๋‹จ์„ ์˜ค๋ฅด๋Š” ๋ฐฉ๋ฒ•์—๋Š” 1๊ฐœ๊ฐ€ ์žˆ์œผ๋ฏ€๋กœ, ์ดˆ๊นƒ๊ฐ’์€ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.
17+
prev1 = 1
18+
prev2 = 0
19+
"""
20+
21+
prev1, prev2 = 1, 0
22+
for _ in range(n):
23+
prev1, prev2 = prev1 + prev2, prev1
24+
return prev1
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# https://leetcode.com/problems/product-of-array-except-self/
2+
3+
from typing import List
4+
5+
class Solution:
6+
def productExceptSelf1(self, nums: List[int]) -> List[int]:
7+
"""
8+
[Complexity]
9+
- TC: O(n)
10+
- SC: O(n)
11+
12+
[Approach]
13+
division operation ์—†์ด ๊ฐ ์›์†Œ๋งˆ๋‹ค ์ž๊ธฐ ์ž์‹ ์„ ์ œ์™ธํ•œ ๋ชจ๋“  ๊ฐ’์˜ ๊ณฑ์„ ๊ตฌํ•ด์•ผํ•˜๋ฏ€๋กœ, ๋‹ค์Œ์˜ ์ˆœ์„œ๋กœ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.
14+
1) ์™ผ์ชฝ ๋ฐฉํ–ฅ์œผ๋กœ ์ˆœํšŒํ•˜๋ฉด์„œ ๊ฐ ์›์†Œ๋ณด๋‹ค ์™ผ์ชฝ์— ์žˆ๋Š” ๊ฐ’๋“ค์˜ ๊ณฑ์œผ๋กœ left ๋ฐฐ์—ด ์ฑ„์šฐ๊ธฐ
15+
2) ์˜ค๋ฅธ์ชฝ ๋ฐฉํ–ฅ์œผ๋กœ ์ˆœํšŒํ•˜๋ฉด์„œ ๊ฐ ์›์†Œ๋ณด๋‹ค ์˜ค๋ฅธ์ชฝ์— ์žˆ๋Š” ๊ฐ’๋“ค์˜ ๊ณฑ์œผ๋กœ right ๋ฐฐ์—ด ์ฑ„์šฐ๊ธฐ
16+
3) left์™€ right ๋ฐฐ์—ด์˜ ์›์†Œ๋งˆ๋‹ค ๊ณฑ์„ ๊ตฌํ•ด์„œ ๊ฒฐ๊ณผ ๋ฐฐ์—ด ๋ฐ˜ํ™˜ํ•˜๊ธฐ
17+
"""
18+
n = len(nums)
19+
20+
left = [1] * n
21+
for i in range(1, n):
22+
left[i] = left[i - 1] * nums[i - 1]
23+
24+
right = [1] * n
25+
for i in range(n - 2, -1, -1):
26+
right[i] = right[i + 1] * nums[i + 1]
27+
28+
return [l * r for l, r in zip(left, right)]
29+
30+
def productExceptSelf(self, nums: List[int]) -> List[int]:
31+
"""
32+
[Complexity]
33+
- TC: O(n)
34+
- SC: O(n) (O(1) extra space)
35+
36+
[Approach]
37+
follow up ์กฐ๊ฑด์„ ์œ„ํ•ด์„œ๋Š” ์ฒซ ๋ฒˆ์งธ ํ’€์ด์ฒ˜๋Ÿผ left, right ๋ฐฐ์—ด์„ ๋‘๋ฉด ์•ˆ ๋˜๊ณ , res ๋ฐฐ์—ด์—์„œ ๊ฐ’์„ ์—…๋ฐ์ดํŠธ ํ•ด๋‚˜๊ฐ€์•ผ ํ•œ๋‹ค.
38+
์ด๋•Œ, O(1) space๋ฅผ ์œ„ํ•ด์„œ ๋ณ€์ˆ˜ prev๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ, ์ˆœํšŒ ์ง„ํ–‰ ๋ฐฉํ–ฅ ๊ธฐ์ค€ ์ด์ „ ๊ฐ’๋“ค์˜ ๊ณฑ์„ ํŠธ๋ž˜ํ‚นํ•ด๋‚˜๊ฐ€๋ฉด ๋œ๋‹ค.
39+
1) nums๋ฅผ ์™ผ์ชฝ ๋ฐฉํ–ฅ์œผ๋กœ ์ˆœํšŒํ•˜๋ฉด์„œ res ๋ฐ prev ๊ฐ’ ์—…๋ฐ์ดํŠธ
40+
2) nums๋ฅผ ์˜ค๋ฅธ์ชฝ ๋ฐฉํ–ฅ์œผ๋กœ ์ˆœํšŒํ•˜๋ฉด์„œ res ๋ฐ prev ๊ฐ’ ์—…๋ฐ์ดํŠธ
41+
"""
42+
n = len(nums)
43+
res = []
44+
45+
prev = 1
46+
for i in range(n):
47+
res.append(prev)
48+
prev *= nums[i]
49+
50+
prev = 1
51+
for i in range(n - 1, -1, -1):
52+
res[i] *= prev
53+
prev *= nums[i]
54+
55+
return res
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# https://leetcode.com/problems/valid-anagram/
2+
3+
class Solution:
4+
def isAnagram1(self, s: str, t: str) -> bool:
5+
"""
6+
[Complexity]
7+
- TC: O(nlogn)
8+
- SC: O(n)
9+
"""
10+
return sorted(s) == sorted(t)
11+
12+
def isAnagram2(self, s: str, t: str) -> bool:
13+
"""
14+
[Complexity]
15+
- TC: O(n)
16+
- SC: O(n)
17+
"""
18+
from collections import Counter
19+
20+
return Counter(s) == Counter(t)
21+
22+
def isAnagram(self, s: str, t: str) -> bool:
23+
"""
24+
[Complexity]
25+
- TC: O(n)
26+
- SC: O(n)
27+
"""
28+
from collections import defaultdict
29+
30+
cnt = defaultdict(int)
31+
32+
for _s in s:
33+
cnt[_s] += 1
34+
for _t in t:
35+
cnt[_t] -= 1
36+
37+
for k, v in cnt.items():
38+
if v != 0:
39+
return False
40+
41+
return True
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
# https://leetcode.com/problems/validate-binary-search-tree/
2+
3+
from typing import Optional
4+
import math
5+
6+
# Definition for a binary tree node.
7+
# class TreeNode:
8+
# def __init__(self, val=0, left=None, right=None):
9+
# self.val = val
10+
# self.left = left
11+
# self.right = right
12+
class Solution:
13+
def isValidBST1(self, root: Optional['TreeNode']) -> bool:
14+
"""
15+
[Complexity]
16+
- TC: O(n) (๋ชจ๋“  node ํ•œ ๋ฒˆ์”ฉ ๋ฐฉ๋ฌธ)
17+
- SC: O(h) (recursion call stack) (balanced tree๋ผ๋ฉด O(logn), skewed tree๋ผ๋ฉด O(n))
18+
19+
[Approach]
20+
validํ•œ BST๋Š” ๋‹ค์Œ์„ ๋งŒ์กฑํ•ด์•ผ ํ•˜๋ฏ€๋กœ recursion์„ ์ด์šฉํ•ด์„œ ํ’€ ์ˆ˜ ์žˆ๋‹ค.
21+
1) left subtree๋Š” less than key
22+
2) right subtree๋Š” greater than key
23+
3) left & right subtree๋„ BST
24+
์ด๋•Œ, ๊ฐ subtree๋ฅผ recursive ํ•˜๊ฒŒ ํƒ€๊ณ  ๋“ค์–ด๊ฐ€์„œ ํ™•์ธํ•˜๋ ค๋ฉด, ๊ฐ ๋‹จ๊ณ„์—์„œ node, min floor val, max ceil val์ด ํ•„์š”ํ•˜๊ณ 
25+
๊ฐ ๋‹จ๊ณ„(= is_valid_subtree())๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ถ„๊ธฐ๋ฅผ ๋‚˜๋ˆ  ์ง„ํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.
26+
1) node๊ฐ€ None์ผ ๋•Œ (base condition): True ๋ฐ˜ํ™˜
27+
2) ํ˜„์žฌ ๋…ธ๋“œ์˜ ๊ฐ’์ธ node.val์ด min floor ~ max ceil ๋ฒ”์œ„์— ํ•ด๋‹นํ•˜์ง€ ์•Š์„ ๋•Œ: False ๋ฐ˜ํ™˜
28+
3) ๊ทธ ์™ธ: left subtree์™€ right subtree๋„ valid ํ•œ์ง€ ์žฌ๊ท€์ ์œผ๋กœ ํ™•์ธ
29+
"""
30+
31+
def is_valid_subtree(node, floor, ceil):
32+
if not node:
33+
return True
34+
35+
if not (floor < node.val < ceil):
36+
return False
37+
38+
return is_valid_subtree(node.left, floor, node.val) and is_valid_subtree(node.right, node.val, ceil)
39+
40+
return is_valid_subtree(root, -math.inf, math.inf)
41+
42+
def isValidBST(self, root: Optional['TreeNode']) -> bool:
43+
"""
44+
[Complexity]
45+
- TC: O(n) (๋ชจ๋“  node ํ•œ ๋ฒˆ์”ฉ ๋ฐฉ๋ฌธ)
46+
- SC: O(n) (recursion call stack O(h) + path O(n))
47+
48+
[Approach]
49+
inorder traversal ํ›„, ์›์†Œ๊ฐ€ ๋ชจ๋‘ ํ•ญ์ƒ strictly ascending sorted ๋˜์–ด ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๋ฉด ๋œ๋‹ค.
50+
"""
51+
52+
path = []
53+
is_asc = True
54+
55+
def inorder(node):
56+
nonlocal is_asc
57+
58+
if not node:
59+
return
60+
61+
inorder(node.left)
62+
63+
# path์— ์›์†Œ๊ฐ€ asc ์ •๋ ฌ๋˜์ง€ ์•Š์€ ์ฑ„๋กœ ๋“ค์–ด๊ฐ„๋‹ค๋ฉด, is_asc = False๋กœ ๋ณ€๊ฒฝ
64+
if path and path[-1] >= node.val:
65+
is_asc = False
66+
path.append(node.val)
67+
68+
inorder(node.right)
69+
70+
inorder(root)
71+
72+
return is_asc

0 commit comments

Comments
ย (0)