Backtrack
Thinking Patterns
抽象地说,解决一个回溯问题,实际上就是遍历一棵决策树的过程,树的每个叶子节点存放着一个合法答案。把整棵树遍历一遍,把叶子节点上的答案都收集起来,就能得到所有的合法答案。
站在回溯树的一个节点上,只需要思考3个问题:
路径. 也就是已经做出的选择。
择列表. 也就是当前可以做的选择。
结束条件. 也就是到达决策树底层,无法再做选择的条件。
Code Template
result = []
def backtrack(path, choices_list):
if can_finish:
result.add(path)
return
for choice in choinces_list:
choose a choice // usually need to update the `path`
backtrack(path, new_choice_list)
cancel the choice // revert the updating to `path`
Problems
Problems - Permutation, Combination and Set Problems
Generally, there are 3 types of classic problems for Permutation
, Combination
and Set
problems. There maybe some other variants from these 3 types.
1. Choose from a list which contains `Non-Duplicate` elements, and element can ONLY be used for ONE time.
2. Choose from a list which contains `Duplicate` elements, and element can ONLY be used for ONE times.
3. Choose from a list which contains `Non-Duplicate` elements, and element can be used for MULTIPLE times.
Thinking Patterns
And the key points of these problems is the backtrack tree
Problems
Types | Problems | Key Points | Possible Solutions | Comments |
---|---|---|---|---|
Permutation Problems | 46 | code | type 1 | |
Permutation Problems | 47 | code | type 2 | |
Combination Problems | 77 | Same as 78 | code | type 1 |
Combination Problems | 216 | code | type 1 | |
Combination Problems | 40 | Prune. Refer to the code. | code | type 2 |
Combination Problems | 39 | code | type 3 | |
Set Problems | 78. Subsets | 1. How to control the flow 2. Complexity analyse |
code | type 1 |
Set Problems | 90 | 1. How to prune. Refer to code | code | type 2 |
- |
Notes
About
Set Problems
.- How to abstract the 3 core questions about the backtrack framework
Time Complexity and Space Complexity
78 Subsets
- Time Complexity
- There are total
2^n
of subsets - For each set, we need to copy
k
number, if there isk
numbers in this subset - So, the overall complexity is
SUM(k*C(n, k))
.k
is the number of elements in the subsets, andC(n, k)
is the number of subsets withk
numbers in it SUM(k * C(n,k)) = n * 2^(n-1)
. So, overall isO(n*2^n)
- There are total
- Space
- The backtrack is around O(n)
- The output is same as time complexity
- Time Complexity
77 Combinations
- Time Complexity
O(k*C(n, k))
,k
is the number of elements in the subset, andC(n, k)
is number of subsets with k numbers in each of them- Space Complexity
- The backtrack is around O(k)
- The output also
O(k*C(n,k))
- Time Complexity
40 Combinations II
- Time Complexity
- Without pruning, roughly about
O(n*2^n)
.- The worst case is to check all the nodes in the recursive tree, that's
O(2^n)
- And need to copy the right answers, which up to O(n)
- So overall, it's around O(n*2^n)
- The worst case is to check all the nodes in the recursive tree, that's
- But with pruning, the time complexity reduce efficiently.
- Without pruning, roughly about
- Space Complexity
- For the backtrack stack space, the worst case would be O(n). If the
target == n
, and all the numbers in candidates are 1 - For the output, if there is
r
results, the worst case would be O(r*n)
- For the backtrack stack space, the worst case would be O(n). If the
- Time Complexity
39 Combination Sum
- Time Complexity
- Recursive call times around O(2^T), T is the
target
- Copy cost of validate result, O(T).
- Overall is O(T*2^T).
- Recursive call times around O(2^T), T is the
- Space Complexity
- Recursive stack, O(T). If all
1
. - Result storage. O(T*R), R is valid number of results
- Recursive stack, O(T). If all
- Time Complexity
46 Permutations
- Time Complexity
- Recursive call times: Count ALL the nodes of the recursive tree: 1 + n + n(n-1) + n(n-1)(n-2) + ... + n! = sum(n!/(n-k)!) where k = 0, 1, ... n, = sum(n!/d!) where d = n-k = n! sum(1/d!) where d = 0, 1, ... n, < n! e so, we have O(en!)
- Copy time cost: O(n)
- Overall: O(n*n!)
- Space complexity
- Recursive call stack: O(n)
visted
array: O(n)- Result storage: O(n*n!)
- Overall: O(n*n!)
- Time Complexity
- 47 Permutations II
- Time Complexity
- Recursive call times: ==> Wrong
- if there are k repeated elements, with pruning:
- then we have 1 + (n-k) + (n-k)(n-k-1) + ... + (n-k)!
- totally we have e*(n-k)! times of recursive call
- Recursive call times: ==> Right
- let
m
as the number of distinct elements Ki
as the repeat times of theith
number inm
- then, the
leaf nodes
aren!/(k1!*K2!*...*Km!)
- let
- Copy time cost O(n)
- Sort (if we use sort):
O(n*lgn)
- Overall
O(n*n!/(K1!*K2!*...*Km!))
- Recursive call times: ==> Wrong
- Space Complexity
- Recursive stack
O(n)
visited
arrayO(n)
hitMap
(if we use map)n + (n-1) + (n-2) + ... + 1 = O(n^2)
- Result store:
O(n*R)
, R is the result, R < n! - R =
n!/(K1!*K2!*...*Km!)
- Recursive stack
- Time Complexity
Type 2 Subset & Combinations pruning. 90, 40
- Check via recursive tree
sort
andnums[i] == nums[i-1]
Problems - Permutation, Combination and Set Problems - Variants
Problems
Problems | Key Points | Possible Solutions | Code | Comments |
---|---|---|---|---|
967. Numbers With Same Consecutive Differences | code | |||
491. Non-decreasing Subsequences | code | Combination Problem type II | ||
980. Unique Paths III | DFS with backtrack | code | Permutation actually | |
131. Palindrome Partitioning | backtrack | code | Combination/Set problems | |
93. Restore IP Addresses | backtrack | code | Combination/Set problems | |
17. Letter Combinations of a Phone Number | backtrack | code | ||
- |
Complexity
980
- O(E!) E is the number of walkable cells. Why not O(m*n)?
- O(m*n)
131
- TC 3 solutions
- O(2^n*n^2)
- O(2^n*n) + O(n^3)
- O(2^n*n) + O(n^2)
- SC
- O(2^n*n) + O(n)
- Refer to the code
- TC 3 solutions
93
- TC
- O(C(n-1, 3)*n). C(n-1, 3) would be roughly 3^4, witch pruning.
- SC
- O(C(n-1, 3)*n)
- TC
17
- TC
- O(3^n*n)
- SC
- O(3^n*n)
- TC
Problems - Variants Problems
Types | Problems | Key Points | Possible Solutions | Comments |
---|---|---|---|---|
Debt Problem | 465 | code |
References
- https://labuladong.online/algo/essential-technique/backtrack-framework/
- https://labuladong.online/algo/essential-technique/permutation-combination-subset-all-in-one/
- https://labuladong.online/algo/practice-in-action/two-views-of-backtrack/
Problems - Others
Problems
Problems | Possible Solutions | Key Points | Code | Comments |
---|---|---|---|---|
494. Target Sum | 1. Backtrack 2. DP |
1. Pruning with memo | code | |
37. Sudoku Solver | backtrack | How to control the flow? Refer to the code | code | |
51. N-Queens | backtrack | How to control the flow? N-Queen v.s. Sudoku Problem | code | |
52. N-Queens II | backtrack | code | ||
- |
Notes
- More about the N-Queen problems
- Time Complexity
- O(N^N) ==> O(N!) with O(1) prune algorithm
cols
,diag1
anddiag2
- Space Complexity
- O(N^2) if store the location data with
board
(n * n matrix) - O(N) with
cols
,diag1
, anddiag2
- O(N^2) if store the location data with
- How does
cols
,diag1
,diag2
work?- 主对角线的特点:所有在同一主对角线上的格子都满足:
row − col = 常数
- 但 row - col 的范围是从 − 𝑁 + 1 到 𝑁 − 1 不能直接作为数组下标
- 所以我们统一加上偏移 𝑁 − 1 把范围映射到 [0, 2N-2]
- 主对角线的特点:所有在同一主对角线上的格子都满足:
- Time Complexity
References