Skip to content

Commit 4cb886c

Browse files
authored
Merge pull request #1276 from seungriyou/main
[seungriyou] Week 03 Solutions
2 parents 9c84199 + 1c238ad commit 4cb886c

File tree

5 files changed

+304
-0
lines changed

5 files changed

+304
-0
lines changed

โ€Žcombination-sum/seungriyou.py

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
# https://leetcode.com/problems/combination-sum/
2+
3+
from typing import List
4+
5+
class Solution:
6+
def combinationSum1(self, candidates: List[int], target: int) -> List[List[int]]:
7+
"""
8+
[Complexity]
9+
- TC: O(n^{target/min(candidates)})
10+
- ์žฌ๊ท€ ํ˜ธ์ถœ ํŠธ๋ฆฌ์˜ ์ตœ๋Œ€ height๋Š” target/min(candidates) (์ค‘๋ณต ๊ฐ€๋Šฅํ•˜๋ฏ€๋กœ)
11+
- ๊ฐ step์—์„œ ์ตœ๋Œ€ nํšŒ ์žฌ๊ท€ ํ˜ธ์ถœ (for i in range(idx, n))
12+
- SC: O(target/min(candidates)) (* res ์ œ์™ธ)
13+
- recursion stack = ์ตœ๋Œ€ O(target/min(candidates))
14+
- combi = ์ตœ๋Œ€ O(target/min(candidates))
15+
16+
[Approach]
17+
backtracking(idx = ํ˜„์žฌ ๋ณด๊ณ ์žˆ๋Š” ์›์†Œ์˜ ์ธ๋ฑ์Šค, tot_sum = ํ˜„์žฌ๊นŒ์ง€์˜ ํ•ฉ)์œผ๋กœ ์ ‘๊ทผํ•œ๋‹ค.
18+
- base condition: tot_sum์ด target๊ณผ ๊ฐ™์œผ๋ฉด res์— ์ถ”๊ฐ€ํ•˜๊ณ , target ๋ณด๋‹ค ํฌ๋ฉด ์ข…๋ฃŒ
19+
- recursion: ํ˜„์žฌ ๋ณด๊ณ ์žˆ๋Š” ์›์†Œ์˜ ์ธ๋ฑ์Šค์˜ ์ดํ›„์— ์žˆ๋Š” ์›์†Œ๋“ค์„ backtracking์œผ๋กœ ๊ฒ€์‚ฌ
20+
(* "same number may be chosen from candidates" ์ด๋ฏ€๋กœ!)
21+
"""
22+
n = len(candidates)
23+
combi = []
24+
res = []
25+
26+
def backtracking(idx, tot_sum):
27+
# base condition
28+
if tot_sum == target:
29+
res.append(combi[:])
30+
return
31+
if tot_sum > target:
32+
return
33+
34+
# recur
35+
for i in range(idx, n):
36+
c = candidates[i]
37+
combi.append(c)
38+
backtracking(i, tot_sum + c)
39+
combi.pop()
40+
41+
backtracking(0, 0)
42+
43+
return res
44+
45+
def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
46+
"""
47+
[Complexity]
48+
- TC: O(n^{target/min(candidates)})
49+
- SC: O(target/min(candidates)) (* res ์ œ์™ธ)
50+
51+
[Approach]
52+
๊ธฐ์กด backtracking ํ’€์ด์— ์ •๋ ฌ์„ ์ถ”๊ฐ€ํ•ด์„œ ์กฐ๊ธˆ ๋” ์ตœ์ ํ™”ํ•  ์ˆ˜ ์žˆ๋‹ค.
53+
์ฆ‰, candidates๋ฅผ ์ •๋ ฌํ•œ ํ›„, ๋งค ๋‹จ๊ณ„์—์„œ candidates[idx] > target - tot_sum ์ผ ๋•Œ๋„ ์ข…๋ฃŒํ•œ๋‹ค.
54+
์ด๋ก ์ ์œผ๋กœ ๋ณต์žก๋„๋Š” ๋™์ผํ•˜๋‚˜(TC์˜ ๊ฒฝ์šฐ, ์ •๋ ฌ์— ๋“œ๋Š” O(nlogn) ๋ณด๋‹ค ๋ฐฑํŠธ๋ž˜ํ‚น์— ๋“œ๋Š” O(n^m)์ด ๋” ์ง€๋ฐฐ์ ), early stop์ด ๊ฐ€๋Šฅํ•ด์ง„๋‹ค.
55+
"""
56+
n = len(candidates)
57+
combi = []
58+
res = []
59+
60+
candidates.sort() # -- ์ •๋ ฌ
61+
62+
def backtracking(idx, tot_sum):
63+
# base condition
64+
if tot_sum == target:
65+
res.append(combi[:])
66+
return
67+
if tot_sum > target or candidates[idx] > target - tot_sum: # -- optimize
68+
return
69+
70+
# recur
71+
for i in range(idx, n):
72+
c = candidates[i]
73+
combi.append(c)
74+
backtracking(i, tot_sum + c)
75+
combi.pop()
76+
77+
backtracking(0, 0)
78+
79+
return res

โ€Ždecode-ways/seungriyou.py

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
# https://leetcode.com/problems/decode-ways/
2+
3+
class Solution:
4+
def numDecodings1(self, s: str) -> int:
5+
"""
6+
[Complexity]
7+
- TC: O(n)
8+
- SC: O(n)
9+
10+
[Approach]
11+
DP๋กœ ํ’€ ์ˆ˜ ์žˆ๋‹ค.
12+
dp[i] = s[i]๊นŒ์ง€ ๋ดค์„ ๋•Œ, ๊ฐ€๋Šฅํ•œ decoding ๊ฐœ์ˆ˜์˜ ์ดํ•ฉ
13+
1) s[i]ย ํ•œ ์ž๋ฆฌ๋งŒ ๊ฐ€๋Šฅํ•œ ๊ฒฝ์šฐ: s[i] != 0
14+
=> dp[i] += dp[i - 1]
15+
2) s[i - 1:i + 1] ๋‘ ์ž๋ฆฌ ๋ชจ๋‘ ๊ฐ€๋Šฅํ•œ ๊ฒฝ์šฐ: 10 <= s[i - 1:i + 1] <= 26
16+
=> dp[i] += dp[i - 2]
17+
๋”ฐ๋ผ์„œ, ์ดˆ๊ธฐ ๊ฐ’์œผ๋กœ dp[0], dp[1]์„ ๋จผ์ € ์ฑ„์›Œ์ฃผ์–ด์•ผ ํ•œ๋‹ค.
18+
"""
19+
20+
n = len(s)
21+
dp = [0] * n
22+
23+
# early stop
24+
if s[0] == "0":
25+
return 0
26+
if n == 1:
27+
return 1
28+
29+
# initialize (dp[0], dp[1])
30+
dp[0] = 1
31+
if s[1] != "0":
32+
dp[1] += dp[0]
33+
if 10 <= int(s[0:2]) <= 26:
34+
dp[1] += 1
35+
36+
# iterate (dp[2] ~)
37+
for i in range(2, n):
38+
# 1) s[i]ย ํ•œ ์ž๋ฆฌ๋งŒ ๊ฐ€๋Šฅํ•œ ๊ฒฝ์šฐ
39+
if s[i] != "0":
40+
dp[i] += dp[i - 1]
41+
# 2) s[i - 1:i + 1] ๋‘ ์ž๋ฆฌ ๋ชจ๋‘ ๊ฐ€๋Šฅํ•œ ๊ฒฝ์šฐ
42+
if 10 <= int(s[i - 1:i + 1]) <= 26:
43+
dp[i] += dp[i - 2]
44+
45+
return dp[-1]
46+
47+
def numDecodings(self, s: str) -> int:
48+
"""
49+
[Complexity]
50+
- TC: O(n)
51+
- SC: O(1)
52+
53+
[Approach]
54+
O(n) space DP์—์„œ ๋งค ๋‹จ๊ณ„์—์„œ dp[i - 1], dp[i - 2] ๋‘ ๊ฐ’๋งŒ ํ™•์ธํ•˜๋ฏ€๋กœ, O(1) space๋กœ space optimize ํ•  ์ˆ˜ ์žˆ๋‹ค.
55+
dp[i - 1] = prev1
56+
dp[i - 2] = prev2
57+
"""
58+
59+
prev2, prev1 = 1, 1 if s[0] != "0" else 0
60+
61+
for i in range(1, len(s)):
62+
curr = 0 # = dp[i]
63+
64+
# 1) s[i]ย ํ•œ ์ž๋ฆฌ๋งŒ ๊ฐ€๋Šฅํ•œ ๊ฒฝ์šฐ
65+
if s[i] != "0":
66+
curr += prev1
67+
# 2) s[i - 1:i + 1] ๋‘ ์ž๋ฆฌ ๋ชจ๋‘ ๊ฐ€๋Šฅํ•œ ๊ฒฝ์šฐ
68+
if 10 <= int(s[i - 1:i + 1]) <= 26:
69+
curr += prev2
70+
71+
prev2, prev1 = prev1, curr
72+
73+
return prev1

โ€Žmaximum-subarray/seungriyou.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# https://leetcode.com/problems/maximum-subarray/
2+
3+
from typing import List
4+
5+
class Solution:
6+
def maxSubArray1(self, nums: List[int]) -> int:
7+
"""
8+
[Complexity]
9+
- TC: O(n)
10+
- SC: O(n)
11+
12+
[Approach]
13+
dp[i] = nums[i]๊นŒ์ง€ ๋ดค์„ ๋•Œ, (1) nums[i]๊ฐ€ ํฌํ•จ๋˜๋ฉด์„œ (2) ๊ฐ€์žฅ sum์ด ํฐ subarray์˜ sum ๊ฐ’
14+
= max(dp[i - 1] + num, num)
15+
"""
16+
17+
n = len(nums)
18+
dp = [0] * n
19+
dp[0] = nums[0]
20+
max_sum = nums[0]
21+
22+
for i in range(1, n):
23+
dp[i] = max(dp[i - 1] + nums[i], nums[i])
24+
max_sum = max(max_sum, dp[i])
25+
26+
return max_sum
27+
28+
def maxSubArray(self, nums: List[int]) -> int:
29+
"""
30+
[Complexity]
31+
- TC: O(n)
32+
- SC: O(1)
33+
34+
[Approach]
35+
space optimized DP
36+
"""
37+
38+
prev = max_sum = nums[0]
39+
40+
for i in range(1, len(nums)):
41+
prev = max(prev + nums[i], nums[i])
42+
max_sum = max(max_sum, prev)
43+
44+
return max_sum

โ€Žnumber-of-1-bits/seungriyou.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# https://leetcode.com/problems/number-of-1-bits/
2+
3+
class Solution:
4+
def hammingWeight1(self, n: int) -> int:
5+
"""
6+
[Complexity]
7+
- TC: O(logn) (์–ด์ฐจํ”ผ O(1))
8+
- SC: O(1)
9+
10+
[Approach]
11+
Bit manipulation์„ ์ด์šฉํ•˜์—ฌ n์ด 0์ด ๋  ๋•Œ๊นŒ์ง€ ๋‹ค์Œ์„ ๋ฐ˜๋ณตํ•œ๋‹ค.
12+
1) ๋งจ ์˜ค๋ฅธ์ชฝ์˜ bit๊ฐ€ 1์ด๋ฉด res์— 1์„ ๋”ํ•˜๊ณ , 0์ด๋ฉด 0์„ ๋”ํ•œ๋‹ค.
13+
2) n์„ ์˜ค๋ฅธ์ชฝ์œผ๋กœ 1 shift ํ•œ๋‹ค.
14+
"""
15+
res = 0
16+
while n:
17+
res += n & 1
18+
n >>= 1
19+
return res
20+
21+
def hammingWeight2(self, n: int) -> int:
22+
"""
23+
[Complexity]
24+
- TC: O(k) (k = number of set bits)
25+
- SC: O(1)
26+
27+
[Approach] Brian Kernighan's Algorithm
28+
์˜ค๋ฅธ์ชฝ์—์„œ๋ถ€ํ„ฐ 1์ธ bit๋ฅผ ํ•˜๋‚˜์”ฉ ์ง€์›Œ๊ฐ€๋ฉฐ ๊ฐœ์ˆ˜๋ฅผ ์„ธ๋ฉด ๋œ๋‹ค.
29+
์ด๋•Œ, ์˜ค๋ฅธ์ชฝ์—์„œ๋ถ€ํ„ฐ 1์ธ bit๋ฅผ ์ง€์šฐ๊ธฐ ์œ„ํ•ด์„œ๋Š” n & n - 1 ์„ ํ•˜๋ฉด ๋œ๋‹ค.
30+
(ref: https://leetcode.com/problems/number-of-1-bits/solutions/4341511/faster-lesser-3-methods-simple-count-brian-kernighan-s-algorithm-bit-manipulation-explained)
31+
"""
32+
res = 0
33+
while n:
34+
n &= n - 1
35+
res += 1
36+
return res
37+
38+
def hammingWeight(self, n: int) -> int:
39+
"""
40+
[Complexity]
41+
- TC: O(logn) (์–ด์ฐจํ”ผ O(1))
42+
- SC: O(1)
43+
44+
[Approach]
45+
n์„ 2๋กœ ๋‚˜๋ˆ„๋ฉด์„œ ๊ทธ ๋‚˜๋จธ์ง€ ๊ฐ’์ด 1์ด๋ฉด res์— 1์„ ๋”ํ•˜๊ณ , 0์ด๋ฉด 0์„ ๋”ํ•œ๋‹ค.
46+
"""
47+
res = 0
48+
while n:
49+
d, m = divmod(n, 2)
50+
res += m
51+
n = d
52+
return res

โ€Žvalid-palindrome/seungriyou.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# https://leetcode.com/problems/valid-palindrome/
2+
3+
class Solution:
4+
def isPalindrome(self, s: str) -> bool:
5+
"""
6+
[Complexity]
7+
- TC: O(n)
8+
- SC: O(n)
9+
10+
[Approach]
11+
1. non-alphanumeric ๋ฌธ์ž๋งŒ lowercase๋กœ ๋ณ€ํ™˜ ํ›„ ๋ฆฌ์ŠคํŠธ์— ๋ชจ์€๋‹ค.
12+
2. 1๋ฒˆ์˜ ๊ฒฐ๊ณผ๋ฅผ ๋’ค์ง‘์–ด๋„ ๋™์ผํ•œ์ง€ ํ™•์ธํ•œ๋‹ค.
13+
"""
14+
15+
s = [_s.lower() for _s in s if _s.isalnum()]
16+
17+
return s == s[::-1]
18+
19+
def isPalindrome1(self, s: str) -> bool:
20+
"""
21+
[Complexity]
22+
- TC: O(n)
23+
- SC: O(n)
24+
25+
[Approach]
26+
1. lowercase๋กœ ๋ณ€ํ™˜ ํ›„ non-alphanumeric์„ ์ œ๊ฑฐํ•œ๋‹ค.
27+
2. 1๋ฒˆ์˜ ๊ฒฐ๊ณผ๋ฅผ ๋’ค์ง‘์–ด๋„ ๋™์ผํ•œ์ง€ ํ™•์ธํ•œ๋‹ค.
28+
"""
29+
import re
30+
31+
_s = re.sub("[^a-z0-9]", "", s.lower())
32+
33+
return _s == _s[::-1]
34+
35+
def isPalindrome2(self, s: str) -> bool:
36+
"""
37+
[Complexity]
38+
- TC: O(n)
39+
- SC: O(n)
40+
41+
[Approach]
42+
1. lowercase๋กœ ๋ณ€ํ™˜ ํ›„ non-alphanumeric์„ ์ œ๊ฑฐํ•œ๋‹ค.
43+
2. 1๋ฒˆ์˜ ๊ฒฐ๊ณผ๋ฅผ ์ ˆ๋ฐ˜๊นŒ์ง€๋งŒ ์ˆœํšŒํ•˜๋ฉฐ, ์–‘๋์—์„œ๋ถ€ํ„ฐ ๋ฌธ์ž๊ฐ€ ๋™์ผํ•œ์ง€ ํ™•์ธํ•œ๋‹ค.
44+
"""
45+
import re
46+
47+
_s = re.sub("[^a-z0-9]", "", s.lower())
48+
49+
def is_palindrome(string):
50+
# ๋ฌธ์ž์—ด์˜ ์ ˆ๋ฐ˜๊นŒ์ง€๋งŒ ์ˆœํšŒํ•˜๋ฉฐ, ์–‘๋์—์„œ๋ถ€ํ„ฐ ๋ฌธ์ž๊ฐ€ ๋™์ผํ•œ์ง€ ํ™•์ธ
51+
for i in range((n := len(string)) // 2):
52+
if string[i] != string[n - i - 1]:
53+
return False
54+
return True
55+
56+
return is_palindrome(_s)

0 commit comments

Comments
ย (0)