491. 非递减子序列
回溯三部曲
1.确定递归函数返回值和参数
返回值为void,参数为给定数组nums,和当前开始遍历的数组索引
2.确定递归终止条件
当遍历开始下标超出数组长度时,中止递归
3.确定回溯单层过程
每层递归中,从当前开始遍历的数组索引开始遍历数组,当当前遍历元素大于等于item中最后一个元素时,将该元素加入item集合
每层递归函数中,如果item中元素数量大于1个,就说明是一个递增子序列,要将当前item插入结果集合中
记得回溯
class Solution {
List<List<Integer>> res = new ArrayList<>();
List<Integer> item = new ArrayList<>();
public List<List<Integer>> findSubsequences(int[] nums) {
backtracking(nums, 0);
return res;
}
private void backtracking(int[] nums, int startIndex){
if(startIndex >= nums.length){
return;
}
Set<Integer> isUsed = new HashSet<>();
for(int i = startIndex; i < nums.length; i++){
//不能用以前的老方法去重,因为数组没有排序,可能会遇见比如说[7,6,7]的情况,这种情况下用过7的话也不能再用,但是用下边注释的方法判断不出来
//改用Set来去重,用过的数字就加入Set中
//if(i > startIndex && nums[i] == nums[i - 1]){
//continue;
//}
if((!item.isEmpty() && nums[i] < item.get(item.size() - 1)) || isUsed.contains(nums[i])){
continue;
}
isUsed.add(nums[i]);
item.add(nums[i]);
if(item.size() > 1){
res.add(new ArrayList<>(item));
}
backtracking(nums, i + 1);
item.remove(item.size() - 1);
}
}
}
——————————————————————————————————————————
46. 全排列
要在同一枝上去重
回溯三部曲
1.确定递归函数返回值和参数
返回值为void,参数为给定数组nums,不需要当前开始遍历的数组索引
2.确定递归终止条件
当单枝集合item加入元素等于nums的长度时,终止递归
3.确定回溯单层过程
每层递归中,从0开始遍历数组,将遍历的元素加入单枝集合item中,同时用一个boolean数组标志数字是否已经加入集合
记得回溯
class Solution {
List<List<Integer>> res = new ArrayList<>();
List<Integer> item = new ArrayList<>();
boolean[] isAdd;
public List<List<Integer>> permute(int[] nums) {
isAdd = new boolean[nums.length];
Arrays.fill(isAdd, false);
backtracking(nums);
return res;
}
private void backtracking(int[] nums){
if(item.size() == nums.length){
res.add(new ArrayList<>(item));
return;
}
for (int i = 0; i < nums.length; i++) {
if(isAdd[i]){
continue;
}
item.add(nums[i]);
isAdd[i] = true;
backtracking(nums);
item.remove(item.size() - 1);
isAdd[i] = false;
}
}
}
——————————————————————————————————————————
47. 全排列 II
要在同一枝上去重,还要在同一层上去重
在同一层上去重用Set去重
回溯三部曲
1.确定递归函数返回值和参数
返回值为void,参数为给定数组nums,不需要当前开始遍历的数组索引
2.确定递归终止条件
当单枝集合item加入元素等于nums的长度时,终止递归
3.确定回溯单层过程
每层递归中,从0开始遍历数组,将遍历的元素加入单枝集合item中,同时用一个boolean数组标志数字是否已经加入集合
记得回溯
class Solution {
List<List<Integer>> res = new ArrayList<>();
List<Integer> item = new ArrayList<>();
boolean[] isAdd;
public List<List<Integer>> permuteUnique(int[] nums) {
isAdd = new boolean[nums.length];
Arrays.fill(isAdd, false);
Arrays.sort(nums);
backtracking(nums);
return res;
}
private void backtracking(int[] nums){
if(item.size() == nums.length){
res.add(new ArrayList<>(item));
return;
}
for (int i = 0; i < nums.length; i++) {
//同一层去重
if(i > 0 && nums[i] == nums[i - 1] && !isAdd[i - 1]){
continue;
}
//同一枝上不要使用已经添加到item中的元素
if (!isAdd[i]) {
item.add(nums[i]);
isAdd[i] = true;
backtracking(nums);
item.remove(item.size() - 1);
isAdd[i] = false;
}
}
}
}