Skip to content

Commit 9ddb4dd

Browse files
Chris WuChris Wu
Chris Wu
authored and
Chris Wu
committed
no message
1 parent e63def2 commit 9ddb4dd

6 files changed

+181
-2
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ https://github.com/wuduhren/leetcode-python
88

99

1010
# Similar Problems
11-
I found it make sense to do similar problems together, so that we can recognize the problem faster when we encounter a new one.
11+
I found it make sense to do similar problems together, so that we can recognize the problem faster when we encounter a new one. My suggestion is to skip the HARD problems when you first go through these list.
1212

1313
### Two Pointers
1414
| Id | Name | Difficulty | Comments |
@@ -36,7 +36,7 @@ I found it make sense to do similar problems together, so that we can recognize
3636
| 46 | [Permutations](https://leetcode.com/problems/permutations/ "Permutations") | ★★ | [47](https://leetcode.com/problems/permutations-ii/ "47") | [784](https://leetcode.com/problems/letter-case-permutation/ "784") | [943](https://leetcode.com/problems/find-the-shortest-superstring "943") | [996](https://leetcode.com/problems/number-of-squareful-arrays/ "996") | | | Permutation |
3737
| 22 | [Generate Parentheses](https://leetcode.com/problems/generate-parentheses/ "Generate Parentheses") | ★★★ | [301](https://leetcode.com/problems/remove-invalid-parentheses/ "301") | | | | | | DFS |
3838
| 37 | [Sudoku Solver](https://leetcode.com/problems/sudoku-solver "Sudoku Solver") | ★★★ | [51](https://leetcode.com/problems/n-queens "51") | [52](https://leetcode.com/problems/n-queens-ii "52") | | | | | DFS |
39-
| 79 | [Word Search](https://leetcode.com/problems/word-search/ "Word Search") | ★★★ | [212](https://leetcode.com/problems/word-search-ii/submissions/ "212") | | | | | | DFS |
39+
| 79 | [Word Search](https://leetcode.com/problems/word-search/ "Word Search") | ★★★ | [212](https://leetcode.com/problems/word-search-ii/ "212") | | | | | | DFS |
4040
| 127 | [Word Ladder](https://leetcode.com/problems/word-ladder/ "Word Ladder") | ★★★★ | [126](https://leetcode.com/problems/word-ladder-ii/ "126") | [752](https://leetcode.com/problems/open-the-lock/ "752") | | | | | BFS |
4141
| 542 | [01 Matrix](https://leetcode.com/problems/01-matrix/ "01 Matrix") | ★★★ | [675](https://leetcode.com/problems/cut-off-trees-for-golf-event/ "675") | [934](https://leetcode.com/problems/shortest-bridge/ "934") | | | | | BFS |
4242
| 698 | [Partition to K Equal Sum Subsets](https://leetcode.com/problems/partition-to-k-equal-sum-subsets "Partition to K Equal Sum Subsets") | ★★★ | [93](https://leetcode.com/problems/restore-ip-addresses/ "93") | [131](https://leetcode.com/problems/palindrome-partitioning/ "131") | [241](https://leetcode.com/problems/different-ways-to-add-parentheses/ "241") | [282](https://leetcode.com/problems/expression-add-operators/ "282") | [842](https://leetcode.com/problems/split-array-into-fibonacci-sequence/ "842") | | Partition |

problems/generate-parentheses.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
"""
2+
If we need `N` pairs of parentheses, we need to use `N` open parenthesis (`open_remain`) and `N` close parenthesis (`close_remain`).
3+
We use `dfs()` to explore all kinds of possiblities.
4+
`open_count` keeps track of how many open parenthesis is in the `path` now. Because number of close parenthesis may not exceed open parenthesis in any given point.
5+
6+
The time complexity is O(2^N), since we can roughly see every position has two options, open or close.
7+
The space complexity is O(2^N), too. And the recuresion level is O(N).
8+
"""
9+
class Solution(object):
10+
def generateParenthesis(self, N):
11+
def dfs(path, open_count, open_remain, close_remain):
12+
if open_remain==0 and close_remain==0:
13+
opt.append(path)
14+
return
15+
if open_count>0 and close_remain>0:
16+
dfs(path+')', open_count-1, open_remain, close_remain-1)
17+
if open_remain>0:
18+
dfs(path+'(', open_count+1, open_remain-1, close_remain)
19+
20+
opt = []
21+
dfs('', 0, N, N)
22+
return opt

problems/letter-case-permutation.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
"""
2+
For each character in the `S` (if it is not a number), it has 2 possibilities, upper or lower.
3+
So starting from an empty string
4+
We explore all the possibilities for the character at index i is upper or lower.
5+
6+
The time complexity is `O(2^N)`.
7+
The space took `O(2^N), too. And the recursion level has N level.
8+
"""
9+
class Solution(object):
10+
def letterCasePermutation(self, S):
11+
def dfs(path, i):
12+
if i>=len(S):
13+
opt.append(path)
14+
return
15+
if S[i] not in num_char:
16+
dfs(path+S[i].upper(), i+1)
17+
dfs(path+S[i].lower(), i+1)
18+
else:
19+
dfs(path+S[i], i+1)
20+
21+
num_char = set(['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'])
22+
opt = []
23+
dfs('', 0)
24+
return opt

problems/permutations-ii.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
"""
2+
This is the extended question of the [first one](https://leetcode.com/problems/permutations/submissions/).
3+
The differece is there will be duplicates in the `nums`.
4+
5+
```python
6+
if i>0 and options[i]==options[i-1]: continue
7+
```
8+
Above lets us skip exploring the same path.
9+
We can directly skip the `i` if the value is the same with `i-1`, because `dfs()` on `i-1` has already cover up all the possiblities.
10+
11+
The time complexity is `O(N!)`.
12+
The space complexity is `O(N!)`, too.
13+
"""
14+
class Solution(object):
15+
def permuteUnique(self, nums):
16+
def dfs(path, options):
17+
if len(path)==len(nums):
18+
opt.append(path)
19+
return
20+
for i, n in enumerate(options):
21+
if i>0 and options[i]==options[i-1]: continue
22+
dfs(path+[n], options[:i]+options[i+1:])
23+
opt = []
24+
nums.sort()
25+
dfs([], nums)
26+
return opt

problems/permutations.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
"""
2+
`nums = [1, 2, 3, 4, 5]`
3+
The first time you choose you can either choose 1 or 2 or 3 or 4 or 5. Lets say you choose 2. So the path so far is `[2]`.
4+
The second time you choose you can only choose 1 or 3 or 4 or 5. Lets say you choose 3. So the path so far is `[2, 3]`.
5+
The third time you choose you can only choose 1 or 4 or 5. Lets say you choose 1. So the path so far is `[2, 3, 1]`.
6+
The third time you choose you can only choose 4 or 5...
7+
.
8+
.
9+
.
10+
11+
We put the numbers we can choose in the `options` parameter. And the path so far in the `path` parameter.
12+
In each `dfs()` we check if the path has used up all the numbers in the `nums`. If true. Append it in the output.
13+
If not, we explore all the posible path in the `options` by `dfs()`.
14+
15+
The time complexity is O(N!). Since in this example our choices is 5 at the beginning, then 4, then 3, then 2, then 1.
16+
The space complexity is O(N!), too. And the recursion takes N level of recursion.
17+
"""
18+
class Solution(object):
19+
def permute(self, nums):
20+
def dfs(path, options):
21+
if len(nums)==len(path):
22+
opt.append(path)
23+
return
24+
for i, nums in enumerate(options):
25+
dfs(path+[nums], options[:i]+options[i+1:])
26+
27+
opt = []
28+
dfs([], nums)
29+
return opt

problems/word-search.py

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
"""
2+
Iterate through the board.
3+
When we spot a starting point, we `dfs()` to see if it can finish the word.
4+
To prevent travel to the visited node, we use a hash-set `set()` to keep track of what we have visited.
5+
`l` is the index of the character in the `word` we are checking.
6+
Note that we need to use `visited.copy()` to copy a whole new hash-set, or all the `dfs()` will use the same hash-set, which is not what we want.
7+
8+
The time complexity is `O(N^2)`, `N` is the number of nodes. You can think of it as for each node, we have to decided to go ot not to go, and we need to make the decision `MN` times.
9+
The space complexity is `O(W*N)`, `W` is the length of `word`. Because the recursion level is `W`, and for each recursion we need to keep track of `visited`, which potensially takes `O(N)`.
10+
"""
11+
class Solution(object):
12+
def exist(self, board, word):
13+
def getNeighbor(i, j):
14+
opt = []
15+
if i+1<M: opt.append((i+1, j))
16+
if j+1<N: opt.append((i, j+1))
17+
if i-1>=0: opt.append((i-1, j))
18+
if j-1>=0: opt.append((i, j-1))
19+
return opt
20+
21+
def dfs(i, j, l, visited):
22+
if l==len(word)-1: return True
23+
visited.add((i, j))
24+
for ni, nj in getNeighbor(i, j):
25+
if (ni, nj) not in visited and board[ni][nj]==word[l+1]:
26+
if dfs(ni, nj, l+1, visited.copy()): return True
27+
return False
28+
29+
M = len(board)
30+
N = len(board[0])
31+
32+
for i in xrange(M):
33+
for j in xrange(N):
34+
if board[i][j]==word[0]:
35+
if dfs(i, j, 0, set()): return True
36+
37+
return False
38+
39+
"""
40+
As you see, the above solution takes lots of space.
41+
Another way is to change the character on the `board` to `#` to represent it as visited.
42+
After the `dfs()` call we need to change it back. Because other branch of `dfs()` might not need visit this node, or haven't visit this node.
43+
44+
The time complexity is `O(N^2)`, `N` is the number of nodes.
45+
The space complexity is `O(W)`, `W` is the length of `word`. Because the recursion level is `W`.
46+
This answer is inspired by @caikehe's [solution](https://leetcode.com/problems/word-search/discuss/27660/).
47+
"""
48+
class Solution(object):
49+
def exist(self, board, word):
50+
def getNeighbor(i, j):
51+
opt = []
52+
if i+1<M: opt.append((i+1, j))
53+
if j+1<N: opt.append((i, j+1))
54+
if i-1>=0: opt.append((i-1, j))
55+
if j-1>=0: opt.append((i, j-1))
56+
return opt
57+
58+
def dfs(i, j, l):
59+
if l==len(word)-1 and board[i][j]==word[l]: return True
60+
if board[i][j]!=word[l]: return False
61+
62+
char = board[i][j]
63+
board[i][j] = '#'
64+
65+
for ni, nj in getNeighbor(i, j):
66+
if dfs(ni, nj, l+1): return True
67+
68+
board[i][j] = char
69+
return False
70+
71+
M = len(board)
72+
N = len(board[0])
73+
74+
for i in xrange(M):
75+
for j in xrange(N):
76+
if dfs(i, j, 0): return True
77+
78+
return False

0 commit comments

Comments
 (0)