Skip to content

Commit e23a7cd

Browse files
authored
Merge pull request DaleStudy#140 from bhyun-kim/main
[bhyun-kim, ๊น€๋ณ‘ํ˜„] Week 8 Solutions
2 parents 10fe2cb + 34c9f96 commit e23a7cd

File tree

6 files changed

+292
-7
lines changed

6 files changed

+292
-7
lines changed

โ€Žcombination-sum/bhyun-kim.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
"""
2+
39. Combination Sum
3+
https://leetcode.com/problems/combination-sum/
4+
5+
Solution
6+
To solve this problem, we can use backtracking.
7+
The idea is to explore all possible combinations starting from each candidate.
8+
9+
- We can sort the candidates to avoid duplicates.
10+
- We can create a helper function that takes the remaining target, the current combination, and the start index.
11+
- If the remaining target is 0, we have found a valid combination, so we add it to the result.
12+
- If the remaining target is negative, we return.
13+
- We iterate through the candidates starting from the start index.
14+
- We add the current candidate to the combination and recursively call the helper function with the updated target and combination.
15+
- After the recursive call, we remove the current candidate from the combination.
16+
17+
Time complexity: O(2^n)
18+
- In the worst case, we explore all possible combinations.
19+
- For each candidate, we have two choices: include it or exclude it.
20+
21+
Space complexity: O(n)
22+
- The recursive call stack has a maximum depth of n.
23+
"""
24+
25+
from typing import List
26+
27+
28+
class Solution:
29+
def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
30+
def backtrack(remain, comb, start):
31+
if remain == 0:
32+
result.append(list(comb))
33+
return
34+
elif remain < 0:
35+
return
36+
37+
for i in range(start, len(candidates)):
38+
current_candidate = candidates[i]
39+
if current_candidate > remain:
40+
break
41+
42+
comb.append(current_candidate)
43+
backtrack(remain - current_candidate, comb, i)
44+
comb.pop()
45+
46+
candidates.sort()
47+
result = []
48+
backtrack(target, [], 0)
49+
return result
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
"""
2+
105. Construct Binary Tree from Preorder and Inorder Traversal
3+
https://leetcode.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/
4+
"""
5+
6+
from typing import List, Optional
7+
8+
9+
# Definition for a binary tree node.
10+
class TreeNode:
11+
def __init__(self, val=0, left=None, right=None):
12+
self.val = val
13+
self.left = left
14+
self.right = right
15+
16+
17+
"""
18+
Solution
19+
To solve this problem, we can use a recursive approach.
20+
We can use a helper function that takes the left and right index of the inorder array.
21+
The helper function will create a root node with the value of the current preorder index.
22+
Then, it will recursively call itself with the left and right index of the left and right subtree.
23+
24+
- Create a dictionary that maps the value of the inorder array to its index.
25+
- Create a variable to keep track of the current preorder index.
26+
- Create a helper function that takes the left and right index of the inorder array.
27+
- In the helper function, if the left index is greater than the right index, return None.
28+
- Create a root node with the value of the current preorder index.
29+
- Increment the preorder index.
30+
- Recursively call the helper function with the left and right index of the left and right subtree.
31+
- Return the root node.
32+
33+
Time Complexity : O(n)
34+
- The helper function is called n times.
35+
- The dictionary lookup is O(1).
36+
37+
Space Complexity : O(n)
38+
- The dictionary has n elements.
39+
- The recursive call stack has n elements.
40+
"""
41+
42+
43+
class Solution:
44+
def buildTree(self, preorder: List[int], inorder: List[int]) -> Optional[TreeNode]:
45+
inorder_index_map = {val: idx for idx, val in enumerate(inorder)}
46+
47+
self.preorder_index = 0
48+
49+
def array_to_tree(left, right):
50+
if left > right:
51+
return None
52+
53+
root_value = preorder[self.preorder_index]
54+
self.preorder_index += 1
55+
56+
root = TreeNode(root_value)
57+
58+
root.left = array_to_tree(left, inorder_index_map[root_value] - 1)
59+
root.right = array_to_tree(inorder_index_map[root_value] + 1, right)
60+
61+
return root
62+
63+
return array_to_tree(0, len(inorder) - 1)
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
"""
2+
208. Implement Trie (Prefix Tree)
3+
https://leetcode.com/problems/implement-trie-prefix-tree/
4+
5+
Solution:
6+
- Initialize the Trie class with an empty list of words.
7+
- Insert a word by appending it to the list of words.
8+
- Search for a word by checking if it is in the list of words.
9+
- Check if a prefix exists by iterating through the list of words and checking if any word starts with the prefix.
10+
11+
Tiem complexity:
12+
- Insert: O(1)
13+
- Appending to a list is O(1)
14+
- Search: O(n)
15+
- Searching for an element in a list is O(n)
16+
- StartsWith: O(n)
17+
- Iterating through a list is O(n)
18+
19+
Space complexity: O(n)
20+
- The list of words may have all the words in the trie.
21+
"""
22+
23+
24+
class Trie:
25+
def __init__(self):
26+
self.words = []
27+
28+
def insert(self, word: str) -> None:
29+
self.words.append(word)
30+
31+
def search(self, word: str) -> bool:
32+
return word in self.words
33+
34+
def startsWith(self, prefix: str) -> bool:
35+
for word in self.words:
36+
if word.startswith(prefix):
37+
return True
38+
39+
return False
40+
41+
42+
# Your Trie object will be instantiated and called as such:
43+
# obj = Trie()
44+
# obj.insert(word)
45+
# param_2 = obj.search(word)
46+
# param_3 = obj.startsWith(prefix)
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
"""
2+
230. Kth Smallest Element in a BST
3+
https://leetcode.com/problems/kth-smallest-element-in-a-bst/
4+
5+
Solution:
6+
To solve this problem, we can use an in-order traversal of the binary search tree.
7+
We can create a helper function that performs an in-order traversal of the tree and returns a list of the elements in sorted order.
8+
Then, we can return the k-th element from the list.
9+
10+
Time complexity: O(n)
11+
- The in-order traversal visits each node once.
12+
- The list concatenation is O(n).
13+
14+
Space complexity: O(n)
15+
- The list of elements has n elements.
16+
"""
17+
18+
19+
from typing import Optional
20+
21+
22+
# Definition for a binary tree node.
23+
class TreeNode:
24+
def __init__(self, val=0, left=None, right=None):
25+
self.val = val
26+
self.left = left
27+
self.right = right
28+
29+
30+
class Solution:
31+
def kthSmallest(self, root: Optional[TreeNode], k: int) -> int:
32+
return self.inOrderSearch(root)[k - 1]
33+
34+
def inOrderSearch(self, root):
35+
output = []
36+
if root:
37+
output += self.inOrderSearch(root.left)
38+
output += [root.val]
39+
output += self.inOrderSearch(root.right)
40+
return output

โ€Žvalidate-binary-search-tree/bhyun-kim.py

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -43,15 +43,12 @@ def isValidBST(self, root: Optional[TreeNode]) -> bool:
4343
return self.isValidSubTree(root, maximum, minimum)
4444

4545
def isValidSubTree(self, root, maximum, minimum):
46-
4746
if root is None:
4847
return True
4948

50-
if not minimum < root.val < maximum:
51-
return False
52-
49+
if not minimum < root.val < maximum:
50+
return False
51+
5352
return self.isValidSubTree(
5453
root.left, root.val, minimum
55-
) and self.isValidSubTree(
56-
root.right, maximum, root.val
57-
)
54+
) and self.isValidSubTree(root.right, maximum, root.val)

โ€Žword-search/bhyun-kim.py

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
"""
2+
79. Word Search
3+
https://leetcode.com/problems/word-search/
4+
5+
Solution:
6+
To solve this problem, we think of the board as a graph.
7+
We can use a depth-first search (DFS) to explore all possible paths starting from each cell.
8+
We can create a helper function that takes the current cell and the index of the current character in the word.
9+
10+
- We can count the frequency of each character in the board.
11+
- We can check if all characters in the word exist in the board.
12+
- If we cannot find all characters in the board, we return False.
13+
14+
- We can create a helper function that takes the current coordinates and the index in the word.
15+
- If the index is equal to the length of the word,
16+
it means we have found all characters in the word, so we return True.
17+
- If the coordinates are out of bounds or the current character does not match,
18+
we return False.
19+
- We mark the current cell as visited and explore all possible directions.
20+
- If any direction returns True, we return True.
21+
- We unmark the current cell and return False.
22+
23+
- We can find all indices of the first character in the word.
24+
- We can start the DFS from each index and return True if any DFS returns True.
25+
- If no DFS returns True, we return False.
26+
27+
Time complexity: O(m*n*4^l)
28+
- m and n are the dimensions of the board.
29+
- l is the length of the word.
30+
- We explore 4 directions at each cell, and the maximum depth is the length of the word.
31+
32+
Space complexity: O(l)
33+
- The recursive call stack has a maximum depth of the length of the word.
34+
35+
"""
36+
37+
38+
from typing import List
39+
40+
41+
class Solution:
42+
def exist(self, board: List[List[str]], word: str) -> bool:
43+
if not board or not word:
44+
return False
45+
46+
m, n = len(board), len(board[0])
47+
48+
# Step 1: Check if all characters in the word exist in the board
49+
char_count = {}
50+
for row in board:
51+
for char in row:
52+
if char in char_count:
53+
char_count[char] += 1
54+
else:
55+
char_count[char] = 1
56+
57+
for char in word:
58+
if char not in char_count or char_count[char] == 0:
59+
return False
60+
char_count[char] -= 1
61+
62+
# Helper function to check if the word can be found starting from (i, j)
63+
def dfs(i, j, word_index):
64+
if word_index == len(word):
65+
return True
66+
67+
if i < 0 or i >= m or j < 0 or j >= n or board[i][j] != word[word_index]:
68+
return False
69+
70+
temp = board[i][j]
71+
board[i][j] = "#" # mark as visited
72+
73+
# Explore all possible directions
74+
found = (
75+
dfs(i + 1, j, word_index + 1)
76+
or dfs(i - 1, j, word_index + 1)
77+
or dfs(i, j + 1, word_index + 1)
78+
or dfs(i, j - 1, word_index + 1)
79+
)
80+
81+
board[i][j] = temp # unmark
82+
return found
83+
84+
# Step 2: Find all indices of the first character in the word
85+
for i in range(m):
86+
for j in range(n):
87+
if board[i][j] == word[0] and dfs(i, j, 0):
88+
return True
89+
90+
return False

0 commit comments

Comments
ย (0)