背景
回溯法(backtrack)常用于遍历列表所有子集,是 DFS 深度搜索一种,一般用于全排列,穷尽所有可能,遍历的过程实际上是一个决策树的遍历过程。时间复杂度一般 O(N!),它不像动态规划存在重叠子问题可以优化,回溯算法就是纯暴力穷举,复杂度一般都很高。
模板
result = []
func backtrack(选择列表,路径):
if 满足结束条件:
result.add(路径)
return
for 选择 in 选择列表:
做选择
backtrack(选择列表,路径)
撤销选择
核心就是从选择列表里做一个选择,然后一直递归往下搜索答案,如果遇到路径不通,就返回来撤销这次选择。
示例
Q****78. Subsets
Given an integer array nums of unique elements, return all possible subsets (the power set). The solution set must not contain duplicate subsets. Return the solution in any order.
Example 1:
Input: nums = [1,2,3]
Output: [[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]
Example 2:
Input: nums = [0]
Output: [[],[0]]
Constraints:
1 <= nums.length <= 10-10 <= nums[i] <= 10- All the numbers of
numsare unique.
解法及注释
class Solution {
public List<List<Integer>> subsets(int[] nums) {
//res to record final result
List<List<Integer>> res = new ArrayList();
//curr to keep current temp result
List<Integer> curr = new ArrayList();
backtrack(nums, 0, curr, res);
return res;
}
private void backtrack(int[] nums, int pos, List<Integer> curr, List<List<Integer>> res) {
//Store the temp list into final result
res.add(new ArrayList(curr));
for(int i = pos; i < nums.length; i++) {
//choose and add
curr.add(nums[i]);
//process result
backtrack(nums, i + 1, curr, res);
//revoke the last one
curr.remove(curr.size() - 1);
}
}
}
Q****90. Subsets II
Given an integer array nums that may contain duplicates, returnall possible subsets (the power set) . The solution set must not contain duplicate subsets. Return the solution in any order.
Example 1:
-
Input: nums = [1,2,2] Output: [[],[1],[1,2],[1,2,2],[2],[2,2]]Example 2:
Input: nums = [0] Output: [[],[0]]Constraints:
1 <= nums.length <= 10-10 <= nums[i] <= 10
解法及注释
class Solution {
public List<List<Integer>> subsetsWithDup(int[] nums) {
List<List<Integer>> res = new ArrayList();
List<Integer> curr = new ArrayList();
Arrays.sort(nums);
backtrack(nums, 0, curr, res);
return res;
}
private void backtrack(int[] nums, int pos, List<Integer> curr, List<List<Integer>> res) {
res.add(new ArrayList(curr));
for(int i = pos; i < nums.length; i++) {
//unchoose the duplicate element if occurrs after sorting
if(i != pos && nums[i] == nums[i - 1])
continue;
curr.add(nums[i]);
backtrack(nums, i + 1, curr, res);
curr.remove(curr.size() - 1);
}
}
}
Q****22. Generate Parentheses
Given n pairs of parentheses, write a function to generate all combinations of well-formed parentheses.
Example 1:
Input: n = 3
Output: ["((()))","(()())","(())()","()(())","()()()"]
Example 2:
Input: n = 1
Output: ["()"]
Constraints:
1 <= n <= 8
解法及注释
class Solution {
public List<String> generateParenthesis(int n) {
List<String> res = new ArrayList();
backtrack(res, "", 0, 0, n);
return res;
}
private void backtrack(List<String> res, String curr, int start, int end, int max) {
if(curr.length() == 2 * max) {
res.add(curr);
return;
}
if(start < max)
backtrack(res, curr+"(", start + 1, end, max);
if(end < start)
backtrack(res, curr+")", start, end + 1, max);
}
}
Q****46. Permutations
Given an array nums of distinct integers, return all the possible permutations. You can return the answer in any order.
Example 1:
Input: nums = [1,2,3]
Output: [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
Example 2:
Input: nums = [0,1]
Output: [[0,1],[1,0]]
Example 3:
Input: nums = [1]
Output: [[1]]
Constraints:
1 <= nums.length <= 6-10 <= nums[i] <= 10- All the integers of
numsare unique.
解法及注释
class Solution {
public List<List<Integer>> permute(int[] nums) {
List<List<Integer>> res = new ArrayList();
List<Integer> curr = new ArrayList();
boolean[] visited = new boolean[nums.length];
backtrack(nums, visited, curr, res);
return res;
}
private void backtrack(int[] nums, boolean[] visited, List<Integer> curr, List<List<Integer>> res) {
if(curr.size() == nums.length)
res.add(new ArrayList(curr));
for(int i = 0; i < nums.length; i++) {
if(visited[i])
continue;
curr.add(nums[i]);
visited[i] = true;
backtrack(nums, visited, curr, res);
//remove element
visited[i] = false;
curr.remove(curr.size() - 1);
}
}
}
Q****47. Permutations II
Given a collection of numbers, nums, that might contain duplicates, return
all possible unique permutations in any order.
Example 1:
Input: nums = [1,1,2]
Output:
[[1,1,2],
[1,2,1],
[2,1,1]]
Example 2:
Input: nums = [1,2,3]
Output: [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
Constraints:
1 <= nums.length <= 8-10 <= nums[i] <= 10
解法及注释
class Solution {
public List<List<Integer>> permuteUnique(int[] nums) {
List<List<Integer>> res = new ArrayList();
List<Integer> curr = new ArrayList();
boolean[] visited = new boolean[nums.length];
Arrays.sort(nums);
backtrack(nums, visited, curr, res);
return res;
}
private void backtrack(int[] nums, boolean[] visited, List<Integer> curr, List<List<Integer>> res) {
if(curr.size() == nums.length)
res.add(new ArrayList(curr));
for(int i = 0; i < nums.length; i++) {
if(visited[i])
continue;
if(i != 0 && nums[i] == nums[i - 1] && !visited[i - 1])
continue;
curr.add(nums[i]);
visited[i] = true;
backtrack(nums, visited, curr, res);
visited[i] = false;
curr.remove(curr.size() - 1);
}
}
}