题型一:排列、组合、子集相关问题
提示:这部分练习可以帮助我们熟悉「回溯算法」的一些概念和通用的解题思路。解题的步骤是:先画图,再编码。去思考可以剪枝的条件, 为什么有的时候用 used 数组,有的时候设置搜索起点 begin 变量,理解状态变量设计的想法。
- 全排列(中等)
- 全排列 II(中等):思考为什么造成了重复,如何在搜索之前就判断这一支会产生重复;
- 组合总和(中等)
- 组合总和 II(中等)
- 组合(中等)
- 子集(中等)
- 子集 II(中等):剪枝技巧同 47 题、39 题、40 题;
- 第 k 个排列(中等):利用了剪枝的思想,减去了大量枝叶,直接来到需要的叶子结点;
- 复原 IP 地址(中等)
目录
题解步骤小总结
1. 先画图、确定递归的树
2. 考虑 每一层开始的位置 begin
组合和子集问题不能从0开始选用 i == start
3. 结束条件
排列是跟踪数组长度== nums.length, 组合target = 0, 子集是 当前层不能继续遍历
4. 剪枝
全排列不用减、组合需要 nums[i] > target不用再搜索、子集不用减枝
5. 去重
核心思想是在递归树的同一层不要使用相同元素去向下搜索,
具体而言可以使用两种方式:
方式一: Set set.contains(nums[i])
方式二:i > 同一层开始的位置 used[i-1] == false;
46. 全排列
难度中等1737
给定一个不含重复数字的数组 nums
,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。
示例 1:
输入:nums = [1,2,3]输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
示例 2:
输入:nums = [0,1]输出:[[0,1],[1,0]]
示例 3:
输入:nums = [1]输出:[[1]]
提示:
1 <= nums.length <= 6
-10 <= nums[i] <= 10
nums
中的所有整数 互不相同
题解
1. 先画图,清楚整个递归回溯的过程。为编码确定细节做准备
2. 是否使用used数组
因为是排列,每个结果集都需要包括所有元素,所以需要用used数组,这样从根节点到子节点遍历的过程中,整个路径就不会有重复的元素。
3. 搜索起点遍历
每一层搜索起点的变量可以从0开始,因为已经使用了used数组来去掉不能使用的元素,然后按照顺序选择第一个不能使用的元素即可
4. 如何去重
没有重复元素不需要去重,保证每个路径是争取的即可
5. 剪枝
判断used数组是不是用就可以帮忙剪枝了
6. 结束条件
存储遍历结果的 curList 长度为nums数组长度就可以结束了
class Solution {
public List<List<Integer>> permute(int[] nums) {
List<List<Integer>> result = new ArrayList();
helper(new ArrayList(), result, nums , new boolean[nums.length]);
return result;
}
private void helper(List<Integer> curList,List<List<Integer>> result, int[]nums, boolean[]used){
if(curList.size() == nums.length){ // 结束条件
result.add(new ArrayList(curList));
} else {
for(int i = 0; i< nums.length; i++){
if(used[i]) continue; // 搜索的过程中,子节点不能和之前节点访问的相同
curList.add(nums[i]);
used[i] = true;
helper(curList, result, nums, used);
curList.remove(curList.size()-1);
used[i] = false;
}
}
}
}
47. 全排列 II
难度中等916
给定一个可包含重复数字的序列 nums
,按任意顺序 返回所有不重复的全排列。
示例 1:
输入:nums = [1,1,2]输出:
[[1,1,2],
[1,2,1],
[2,1,1]]
示例 2:
输入:nums = [1,2,3]输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
题解
方法一:
Set<Integer> curDepthUsedSet = new HashSet<>(); //记录每一层使用过的节点
通过Set记录当前层使用过的节点数值,从而保证了当前层只能使用相同数值一次
class Solution {
public List<List<Integer>>