Intro
Backtracking is usually used when you have multiple solutions and you need all the solutions. if we want a best solution(optimal) that would be Dynamic Programming problem
State Space Tree
Video: https://www.youtube.com/watch?v=DKCbsiDBN6c&t=8s
Brute Force Approach: https://www.youtube.com/watch?v=vtnpzDPgaU0
- We would like to construct an algorithm that’s capable of finding a pattern in a text
- Keep iterating through the text and if there’s a mismatch, we shift the pattern one step to the right
- Problem: needs to back up for every mismatch
DFS Approach
Branch and Bound
Condition: Bounding function -> kill the tree branch that is not satisfied with condition.
22. Generate Parentheses
Leetcode: https://leetcode.com/problems/generate-parentheses/description/
[Solution]
- First must be ‘(‘, last one must be ‘)’
- Conditions
- Nums of ‘(‘ <= nums of ‘)’ during traversal
- Nums of ‘(‘ or ‘)’ <= n / 2
1 | class Solution { |
17. Letter Combinations of a phone number
Leetcode: https://leetcode.com/problems/letter-combinations-of-a-phone-number/description/
[Solution]1
2
3
4
5
6
7Tree Traversal
Traverse(root, s):
s += root;
if (s.length == 3) result.add(s); s-> ""
if (c1) traverse(root.c1)
if (c2) traverse(root.c2)
if (c3) traverse(root.c3)
1 | import java.util.ListIterator; |
46. Permutations
1 | class Solution { |
1 | def permute(self, nums: List[int]) -> List[List[int]]: |
Permutaions II
Leetcode: https://leetcode.com/problems/permutations-ii/
Note:
We use a counter dictionary to track unique elements and how many of them has been used.
1 | def permuteUnique(self, nums: List[int]) -> List[List[int]]: |
526. Beautiful Arrangement
Leetcode: https://leetcode.com/problems/beautiful-arrangement/
1 | def countArrangement(self, n: int) -> int: |
77.Combinations
Leetcode: https://leetcode.com/problems/combinations/description/
Solution:
- Use
first
index to mark the current position, will help prevent repetitions
1 | def combine(self, n: int, k: int) -> List[List[int]]: |
39. Combination Sum
Leetcode: https://leetcode.com/problems/combination-sum/description/
Video: https://www.youtube.com/watch?v=aBL-aNWNmB4
[Solution] Recursively solve the problem. Use a target to keep track of each layer.
1 | const combinationSum = (candidates, target) => { |
40. Combination Sum II
Leetcode: https://leetcode.com/problems/combination-sum-ii/description/
1 | const combinationSum2 = (candidates, target) => { |
Concise version
1 | var combinationSum2 = function(candidates, target) { |
216. Combination Sum III
Leetcode: https://leetcode.com/problems/combination-sum-iii/description/
1 | const combinationSum3 = (k, target) => { |
377. Combination Sum IV
Leetcode: https://leetcode.com/problems/combination-sum-iv/
Note: Use memoization.
1 | var combinationSum4 = function(nums, target) { |
78. Subsets
Leetcode: https://leetcode.com/problems/subsets/submissions/
1 | def subsets(self, nums: List[int]) -> List[List[int]]: |
90. Subsets II
Leetcode: https://leetcode.com/problems/subsets-ii/
1 | def subsetsWithDup(self, nums: List[int]) -> List[List[int]]: |
139. Word Break
Leetcode: https://leetcode.com/problems/word-break/
- Backtrack, memoization, trie
- Dynamic Programming solution see DP chapter
1 | def wordBreak(self, s: str, wordDict: List[str]) -> bool: |
140. Word Break II
Leetcode: https://leetcode.com/problems/word-break-ii/
Backtracking solution (Time limit exceeds):1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18var wordBreak = function(s, wordDict) {
let set = new Set([...wordDict]);
let res = [];
const backtrack = (leftString, cur) => {
if (set.has(leftString)) {
res.push(cur + ` ${leftString}`);
}
for (let i = 0; i < leftString.length; i++) {
let sub = leftString.substring(0, i);
if (set.has(sub)) {
backtrack(leftString.substring(i, leftString.length), cur + ` ${sub}`);
}
}
}
backtrack(s, "");
return res;
};
To improve the time complexity, we can try to:
- use a dictionary to memoize the
1 | def wordBreak(self, s, wordDict): |
131. Palindrome Partitioning
Leetcode: https://leetcode.com/problems/palindrome-partitioning/
1 | var partition = function(s) { |
698. Partition to K Equal Sum Subsets
Leetcode: https://leetcode.com/problems/partition-to-k-equal-sum-subsets/
Video: https://www.youtube.com/watch?v=qpgqhp_9d1s&t=311s
Starting from filling 1 bucket, then 2, then 3… If there’s only one bucket unfilled left, then return true
.
1 | var canPartitionKSubsets = function(nums, k) { |
51. N-Queens
Leetcode: https://leetcode.com/problems/n-queens/
1 | def solveNQueens(self, n: int) -> List[List[str]]: |
489. Robot Room Cleaner
Leetcode: https://leetcode.com/problems/robot-room-cleaner/
Spiral Backtracking: Move the robot in a spiral way, if robot is surrounded by walls and visited nodes, backtrack to the previous alternative route.
1 | def cleanRoom(self, robot): |
282. Expression Add Operators
Leetcode: https://leetcode.com/problems/expression-add-operators/
1 | def addOperators(self, num, target): |
93. Restore IP Addresses
Leetcode: https://leetcode.com/problems/restore-ip-addresses/
Note:
- A lot of edge cases to consider
- In each recursion layer, we add first three digits to the current number
1 | def restoreIpAddresses(self, s): |