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 
firstindex 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):  |