Day26 第七章 回溯算法part05
一. 学习文章及资料
- 491.递增子序列
- 46.全排列
- 47.全排列 II
二. 学习内容
1. 递增子序列
(1) 题目要点:
- 递增子序列,
- 数组中可能含有重复元素
(2) 解题思路:
如下一选取元素不是递增或使用过,则跳过这一分支,用set记录已使用元素以达去重效果
class Solution {
List<List<Integer>> result=new ArrayList<>();
List<Integer> path=new LinkedList<>();
void backtracking(int[] nums,int startIndex){
if(path.size()>=2){
result.add(new ArrayList(path));
}
HashSet<Integer> hs=new HashSet<>();
for(int i=startIndex;i<nums.length;i++){
if(!path.isEmpty()&&path.get(path.size()-1)>nums[i]||hs.contains(nums[i])){//如下一个数不是递增或使用过,则跳过
continue;
}
hs.add(nums[i]);
path.add(nums[i]);
backtracking(nums,i+1);
path.removeLast();
}
return;
}
public List<List<Integer>> findSubsequences(int[] nums) {
backtracking(nums,0);
return result;
}
}
2. 全排列
(1) 解题要点:
- 没有重复数字
- 返回其所有可能的全排列
(2) 解题思路:
首先排列是有序的,也就是说 [1,2] 和 [2,1] 是两个集合,这和之前分析的子集以及组合所不同的地方。可以看出元素1在[1,2]中已经使用过了,但是在[2,1]中还要在使用一次1,所以处理排列问题就不用使用startIndex了,每层i都从0开始,使用used数组记录使用情况
class Solution {
List<List<Integer>> result=new ArrayList<>();
List<Integer> path=new LinkedList<>();
void backtracking(int[] nums,boolean[] used){
if(path.size()==nums.length){
result.add(new ArrayList(path));
}
for(int i=0;i<nums.length;i++){
if(used[i]==true) continue;
used[i]=true;
path.add(nums[i]);
backtracking(nums,used);
path.removeLast();
used[i]=false;
}
return;
}
public List<List<Integer>> permute(int[] nums) {
boolean[] used=new boolean[nums.length];
backtracking(nums,used);
return result;
}
}
3. 全排列 II
(1) 题目要点:
- 包含重复数字
- 返回所有不重复的全排列
(2) 题目思路:
以示例中的 [1,1,1]为例 (为了方便举例,已经排序)抽象为一棵树,去重过程如图:
图中我们对同一树层,前一位(也就是nums[i-1])如果使用过,那么就进行去重。
要强调的是去重一定要对元素进行排序,这样我们才方便通过相邻的节点来判断是否重复使用了。
组合问题和排列问题是在树形结构的叶子节点上收集结果,而子集问题就是取树上所有节点的结果。
class Solution {
List<List<Integer>> result=new ArrayList<>();
List<Integer> path=new LinkedList<>();
void backtracking(int[] nums,boolean[] used){
if(path.size()==nums.length){
result.add(new ArrayList(path));
return;
}
for(int i=0;i<nums.length;i++){
// used[i - 1] == true ,说明同一树枝nums[i - 1]使用过
// used[i - 1] == false,说明同一树层nums[i - 1]使用过
if(i>0&&nums[i]==nums[i-1]&&used[i-1]==false) continue;//防止一种数字重复使用
if(used[i]==false){//每个元素数只能用一次,防止重复使用
path.add(nums[i]);
used[i]=true;
backtracking(nums,used);
used[i]=false;
path.removeLast();
}
}
}
public List<List<Integer>> permuteUnique(int[] nums) {
boolean[] used = new boolean[nums.length];
Arrays.sort(nums);
backtracking(nums,used);
return result;
}
}