-
Notifications
You must be signed in to change notification settings - Fork 126
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #731 from dusunax/main
[SunaDu] Week 2
- Loading branch information
Showing
5 changed files
with
340 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
''' | ||
# Leetcode 15. 3Sum | ||
use **two pointers** to solve this problem. | ||
## Time and Space Complexity | ||
``` | ||
TC: O(n^2) | ||
SC: O(1) | ||
``` | ||
### TC is O(n^2): | ||
- sorting the list = O(n log n) | ||
- iterating through the list and using two pointers to find the sum of three numbers. = O(n^2) | ||
### SC is O(1): | ||
- sorting in place = O(1) | ||
''' | ||
|
||
class Solution: | ||
def threeSum(self, nums: List[int]) -> List[List[int]]: | ||
nums.sort() # TC: O(n log n), SC: O(1) | ||
result = [] # result are part of the output => do not count toward auxiliary (extra) space. | ||
|
||
for i in range(len(nums)): # TC: O(n^2) | ||
if i > 0 and nums[i] == nums[i - 1]: | ||
continue | ||
|
||
j = i + 1 | ||
k = len(nums) - 1 | ||
while j < k: | ||
currSum = nums[i] + nums[j] + nums[k] | ||
|
||
if currSum < 0: | ||
j += 1 | ||
elif currSum > 0: | ||
k -= 1 | ||
else: | ||
result.append([nums[i], nums[j], nums[k]]) | ||
|
||
while j < k and nums[j] == nums[j + 1]: | ||
j += 1 | ||
while j < k and nums[k] == nums[k - 1]: | ||
k -= 1 | ||
|
||
j += 1 | ||
k -= 1 | ||
|
||
return result |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
''' | ||
# Leetcode 70. Climbing Stairs | ||
use `dynamic programming` to solve the problem. | ||
1. Bottom-up approach | ||
2. Top-down approach | ||
## Time and Space Complexity | ||
### 1. Bottom-up approach | ||
``` | ||
TC: O(n) | ||
SC: O(1) | ||
``` | ||
#### TC is O(n): | ||
- iterating with a for loop. O(n) | ||
#### SC is O(1): | ||
- using a constant space to store the previous two steps. O(1) | ||
### 2. Top-down approach | ||
``` | ||
TC: O(n) | ||
SC: O(n) | ||
``` | ||
#### TC is O(n): | ||
- performing a recursive call for each step. O(n) | ||
#### SC is O(n): | ||
- using a memoization object to store the previous two steps. O(n) | ||
''' | ||
|
||
class Solution: | ||
''' | ||
1. Bottom-up approach | ||
''' | ||
def climbStairsLoop(self, n: int) -> int: | ||
if n == 1 or n == 2: | ||
return n | ||
|
||
# SC: O(1) | ||
prev2 = 1 # ways to step 0 | ||
prev1 = 2 # ways to step 1 | ||
|
||
for i in range(3, n + 1): # TC: O(n) | ||
current = prev1 + prev2 # ways to (n-1) + (n-2) | ||
prev2 = prev1 | ||
prev1 = current | ||
|
||
return prev1 | ||
|
||
''' | ||
2. Top-down approach | ||
''' | ||
def climbStairsRecursive(self, n: int) -> int: | ||
memo = {} # SC: O(n) | ||
|
||
def dp(step: int, memo: int) -> int: # TC: O(n) | ||
if step == 1 or step == 2: | ||
memo[step] = step | ||
if step not in memo: | ||
memo[step] = dp(step - 1, memo) + dp(step - 2, memo) # ways to (n-1) + (n-2) | ||
return memo[step] | ||
|
||
return dp(n, memo) | ||
|
119 changes: 119 additions & 0 deletions
119
construct-binary-tree-from-preorder-and-inorder-traversal/dusunax.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
|
||
''' | ||
# Leetcode 105. Construct Binary Tree from Preorder and Inorder Traversal | ||
use **recursive** to solve this problem. | ||
## Time and Space Complexity | ||
### A. recursive & change range of preorder and inorder | ||
``` | ||
TC: O(n) | ||
SC: O(n) | ||
``` | ||
### B. recursive & search index (of inorder) | ||
``` | ||
TC: O(n^2) | ||
SC: O(n) | ||
``` | ||
### C. recursive & hash table | ||
``` | ||
TC: O(n) | ||
SC: O(n) | ||
``` | ||
''' | ||
class Solution: | ||
''' | ||
A. ์ฌ๊ท ํ์ด | ||
preorder์ inorder์ ๊ฐ๊ฐ์ ๋ฒ์๋ฅผ ์กฐ์ ํ์ฌ ํธ๋ฆฌ๋ฅผ ์์ฑ | ||
''' | ||
def buildTreeA(self, preorder: List[int], inorder: List[int]) -> Optional[TreeNode]: | ||
def setTree(pre_left, pre_right, in_left, in_right): | ||
# ์ฌ๊ท ์ข ๋ฃ ์กฐ๊ฑด: preorder ๋ฒ์๊ฐ ์ ํจํ์ง ์์ ๊ฒฝ์ฐ | ||
if pre_left > pre_right: | ||
return None | ||
|
||
val = preorder[pre_left] # preorder์ ํ์ฌ ๋ฃจํธ ๋ ธ๋ ๊ฐ ๊ฐ์ ธ์ค๊ธฐ | ||
mid = TreeNode(val) # ๋ฃจํธ ๋ ธ๋๋ฅผ ๋จผ์ ์์ฑ | ||
|
||
mid_inorder = inorder_idx_map[val] # ๋ฃจํธ ๋ ธ๋์ inorder ์ธ๋ฑ์ค ๊ฐ์ ธ์ค๊ธฐ | ||
left_size = mid_inorder - in_left # ์ผ์ชฝ ์๋ธํธ๋ฆฌ์ ํฌ๊ธฐ ๊ณ์ฐ | ||
|
||
# ์ผ์ชฝ ์๋ธํธ๋ฆฌ ์์ฑ: preorder์ inorder์ ๋ฒ์๋ฅผ ์ผ์ชฝ ์๋ธํธ๋ฆฌ๋ก ์กฐ์ | ||
mid.left = setTree( | ||
pre_left + 1, pre_left + left_size, in_left, mid_inorder - 1 | ||
) | ||
|
||
# ์ค๋ฅธ์ชฝ ์๋ธํธ๋ฆฌ ์์ฑ: preorder์ inorder์ ๋ฒ์๋ฅผ ์ค๋ฅธ์ชฝ ์๋ธํธ๋ฆฌ๋ก ์กฐ์ | ||
mid.right = setTree( | ||
pre_left + left_size + 1, pre_right, mid_inorder + 1, in_right | ||
) | ||
|
||
return mid # ํ์ฌ ๋ ธ๋ ๋ฐํ | ||
|
||
# inorder๋ฅผ ๊ฐ -> ์ธ๋ฑ์ค ๋งตํํ ๋์ ๋๋ฆฌ ์์ฑ - TC: O(n), SC: O(n) | ||
inorder_idx_map = {value: idx for idx, value in enumerate(inorder)} | ||
|
||
# ํธ๋ฆฌ ์์ฑ ์์ (preorder์ inorder ์ ์ฒด ๋ฒ์ ์ฌ์ฉ) - TC: O(n), SC: O(n) | ||
return setTree(0, len(preorder) - 1, 0, len(inorder) - 1) | ||
|
||
|
||
''' | ||
# B. ์ฌ๊ท ํ์ด + ๊ณต๊ฐ ์ต์ ํ | ||
# ๋ ํผ๋ฐ์ค ๋งํฌ์ ํ์ด 2: https://www.algodale.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/ | ||
# ํน์ง: ์ํ ์๋ง๋ค ์ธ๋ฑ์ค๋ฅผ ์ฐพ๋ ๊ณผ์ ์ด ์์ | ||
''' | ||
def buildTreeB(self, preorder: List[int], inorder: List[int]) -> Optional[TreeNode]: | ||
# pre: ํ์ฌ preorder์์ ํ์ธํ ์ธ๋ฑ์ค | ||
# start, end: inorder์์ ์ฌ์ฉํ ์์/์ข ๋ฃ ๋ฒ์ | ||
def setTree(pre, start, end): | ||
# ์ฌ๊ท ์ข ๋ฃ ์กฐ๊ฑด: ๋ฒ์๊ฐ ์๋ชป๋์๊ฑฐ๋ ํธ๋ฆฌ๋ฅผ ๋ ์ด์ ๋ง๋ค ํ์๊ฐ ์๋ ๊ฒฝ์ฐ | ||
if not (pre < len(preorder) and start <= end): # preorder์์ ํ์ธํ ์ธ๋ฑ์ค๊ฐ ๋ฒ์์์ ๋๊ฐ, ํฌ ํฌ์ธํฐ๊ฐ ๋ง๋จ | ||
return None | ||
|
||
val = preorder[pre] # ํ์ฌ ๋ ธ๋์ ๊ฐ | ||
root = inorder.index(val) # ํธ๋ฆฌ/์๋ธํธ๋ฆฌ์ ๋ฃจํธ ๋ ธ๋ ์ธ๋ฑ์ค ์ฐพ๊ธฐ - TC: O(n) | ||
|
||
left = setTree(pre + 1, start, root - 1) | ||
# inorder์์ root๋ ธ๋์ ์ผ์ชฝ์ ์ผ์ชฝ ์๋ธํธ๋ฆฌ | ||
# pre์ ๋ณํ: ์ผ์ชฝ ์๋ธํธ๋ฆฌ์ ๋ฃจํธ ๋ ธ๋๋ฅผ ์ฐพ๊ธฐ ์ํด +1 ์ด๋ | ||
|
||
right = setTree(pre + 1 + root - start, root + 1, end) | ||
# inorder์์ root๋ ธ๋์ ์ค๋ฅธ์ชฝ์ ์ค๋ฅธ์ชฝ ์๋ธํธ๋ฆฌ | ||
# pre์ ๋ณํ: ์ค๋ฅธ์ชฝ ์๋ธํธ๋ฆฌ์ ๋ฃจํธ ๋ ธ๋๋ฅผ ์ฐพ๊ธฐ ์ํด +1 ์ด๋ + (root - start) ๐ ์ผ์ชฝ ์๋ธํธ๋ฆฌ์ ํฌ๊ธฐ ๋งํผ ๋ ์ด๋ | ||
|
||
return TreeNode(preorder[pre], left, right) # ํธ๋ฆฌ ๋ ธ๋ ์์ฑ | ||
|
||
# preorder ์ต์ด ์ธ๋ฑ์ค = ๋ฃจํธ ๋ ธ๋(0), inorder์ ์ฒ์(0)๊ณผ ๋(len(inorder) - 1) ์ธ๋ฑ์ค | ||
return setTree(0, 0, len(inorder) - 1) # TC: O(n^2), SC: O(n) | ||
|
||
''' | ||
C. ์ฌ๊ท ํ์ด + ์๊ฐ ์ต์ ํ | ||
๋ ํผ๋ฐ์ค ๋งํฌ์ ํ์ด 3: https://www.algodale.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/ | ||
ํน์ง: A์์ preorder๋ฅผ ์ฐพ๋ O(n) ๊ณผ์ ์ ํด์ ํ ์ด๋ธ์ ์ฌ์ฉํ์ฌ O(1)๋ก ์ต์ ํ | ||
''' | ||
def buildTreeC(self, preorder: List[int], inorder: List[int]) -> Optional[TreeNode]: | ||
# enumerate: ์ธ๋ฑ์ค์ ๊ฐ์ ๋์์ ๋ฐํ | ||
# inorder๋ฅผ val -> idx๋ก ๋งคํํ ๋์ ๋๋ฆฌ ์์ฑ | ||
inorder_index_map = {val: idx for idx, val in enumerate(inorder)} | ||
# preorder๋ฅผ ์ํํ๊ธฐ ์ํ iterator ๊ฐ์ฒด ์์ฑ | ||
pre_iter = iter(preorder) | ||
|
||
def setTree(start, end): | ||
if start > end: # ์ฌ๊ท ์ข ๋ฃ ์กฐ๊ฑด: ๋ฒ์๊ฐ ์๋ชป๋์๊ฑฐ๋ ํธ๋ฆฌ๋ฅผ ๋ ์ด์ ๋ง๋ค ํ์๊ฐ ์๋ ๊ฒฝ์ฐ | ||
return None | ||
|
||
root_val = next(pre_iter) # ํ์ฌ ๋ ธ๋์ ๊ฐ, ๋งค ์ํ๋ง๋ค ๋ค์ preorder ๋ ธ๋(root)์ ๊ฐ์ ๊ฐ์ ธ์ด | ||
root = inorder_index_map[root_val] # ํธ๋ฆฌ/์๋ธํธ๋ฆฌ์ ๋ฃจํธ ๋ ธ๋ ์ธ๋ฑ์ค๋ฅผ O(1) ์๊ฐ์ผ๋ก ์ฐพ๊ธฐ | ||
|
||
left = setTree(start, root - 1) # ์ผ์ชฝ ์๋ธํธ๋ฆฌ | ||
right = setTree(root + 1, end) # ์ค๋ฅธ์ชฝ ์๋ธํธ๋ฆฌ | ||
return TreeNode(root_val, left, right) # ํธ๋ฆฌ ๋ ธ๋ ์์ฑ | ||
|
||
return setTree(0, len(inorder) - 1) # inorder์ ์ฒ์(0)๊ณผ ๋(len(inorder) - 1) ์ธ๋ฑ์ค |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
''' | ||
# Leetcode 91. Decode Ways | ||
use **dynamic programming** to solve this problem. | ||
## Time and Space Complexity | ||
``` | ||
TC: O(n) | ||
SC: O(n) | ||
``` | ||
### TC is O(n): | ||
- iterating through the string and checking if the current character is decodable. = O(n) | ||
### SC is O(n): | ||
- creating a dp array of size n + 1 = O(n) | ||
''' | ||
class Solution: | ||
def isDecodable(self, str: str): | ||
return 1 <= int(str) <= 26 and str[0] != '0' | ||
|
||
def numDecodings(self, s: str) -> int: | ||
if s[0] == "0": | ||
return 0 | ||
|
||
n = len(s) | ||
dp = (n + 1) * [0] | ||
dp[0] = 1 | ||
dp[1] = 1 | ||
|
||
for i in range(2, n + 1): | ||
one = s[i - 1] | ||
two = s[i - 2:i] | ||
|
||
if self.isDecodable(one): | ||
dp[i] += dp[i - 1] | ||
if self.isDecodable(two): | ||
dp[i] += dp[i - 2] | ||
|
||
return dp[n] | ||
|
||
''' | ||
# sudo code | ||
- ํฌํผํจ์: 0์ผ๋ก ์์ํ์ง ์๊ณ , 1~26์ธ ๊ฒฝ์ฐ True | ||
- numDecodingsํจ์ | ||
1. n: ๋ฌธ์์ด s์ ๊ธธ์ด | ||
2. dp: ๊ฒฐ๊ณผ๋ฅผ ์ ์ฅํ ๋ฐฐ์ด, n+1 | ||
3. BaseCase: dp[0] = 1, dp[1] = 1 | ||
4. for loop 2 to n: | ||
one = s์ i-1 ์์น์ 1๊ธ์ (ํ์ฌ ๊ธ์) | ||
two = s์ i-2๋ถํฐ i๊น์ง ์๋ฅธ 2๊ธ์ (ํ์ฌ ๊ธ์ ํฌํจ ์ด์ ๊ธ์) | ||
if one is decodable => dp[i] += dp[i - 1] i๊ธธ์ด์ผ ๋, dp์ -1 ๊ฒฝ์ฐ์ ๋งํผ์ ์ถ๊ฐ (ํ์ฌ ๊ธ์๋ฅผ ํ ๊ธ์๋ก ํด์) | ||
if two is decodable => dp[i] += dp[i - 2] i๊ธธ์ด์ผ ๋, dp์ -2 ๊ฒฝ์ฐ์ ์ ๋งํผ ์ถ๊ฐ (ํ์ฌ ๊ธ์๋ฅผ ๋ ๊ธ์๋ก ํด์) | ||
5. dp[n] ๋ฐํ: ์ต์ข ๋์ฝ๋ ๊ฐ๋ฅํ ๊ฒฝ์ฐ์ ์ ๊ฒฐ๊ณผ | ||
''' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
''' | ||
# Leetcode 242. Valid Anagram | ||
use `Counter` to (1)compare the frequency of characters in both strings, and (2)try to compare the frequency more efficiently. ๐ | ||
## Time and Space Complexity | ||
``` | ||
TC: O(n) | ||
SC: O(n) | ||
``` | ||
### A. use frequency object | ||
#### TC is O(n): | ||
- iterating through the strings just once to compare the frequency of characters. O(n) | ||
#### SC is O(n): | ||
- creating a new string `converted_s` to store the | ||
### B. use Counter more efficiently | ||
#### TC is O(n): | ||
- iterating through the strings just once to compare the frequency of characters. O(n) | ||
#### SC is O(n): | ||
- creating a new string `converted_s` to store the | ||
''' | ||
class Solution: | ||
def isAnagramA(self, s: str, t: str) -> bool: | ||
if len(s) != len(t): | ||
return False | ||
|
||
frequency = Counter(s) # SC: O(n) | ||
|
||
for char in t: # TC: O(n) | ||
if char not in frequency or frequency[char] == 0: # TC: O(1) | ||
return False | ||
frequency[char] -= 1 | ||
|
||
return True | ||
|
||
def isAnagramB(self, s: str, t: str) -> bool: | ||
return Counter(s) == Counter(t) # TC: O(n), SC: O(n) |