491. 递增子序列
链接: 参考讲解
- 遇到的困难
对递归终止条件不太清楚,第一次写的时候加了return并不知道要取树上的节点。
class Solution {
List<List<Integer>> res = new ArrayList<>();
LinkedList<Integer> path = new LinkedList<>();
public List<List<Integer>> findSubsequences(int[] nums) {
backtrack(nums,0);
return res;
}
public void backtrack(int[] nums, int startIndex){
if(path.size() >= 2){
res.add(new ArrayList<>(path));
// 注意这里不要加return,要取树上的节点
}
HashSet<Integer> set = new HashSet<>(); // 用来记录本层遍历的数字
for(int i = startIndex; i<nums.length; i++){
if(!path.isEmpty() && nums[i] < path.getLast()
|| set.contains(nums[i])) continue;
set.add(nums[i]); // 记录这个元素在本层用过了,本层后面不能再用了
path.add(nums[i]);
backtrack(nums,i+1);
path.removeLast();
}
}
}
46. 全排列
链接: 参考讲解
去重是关键,这里又用到了used数组,在这里used数组不再作为数层的标记,而是负责树枝的修剪
class Solution {
List<List<Integer>> res = new ArrayList<>();
LinkedList<Integer> path = new LinkedList<>();
boolean[] used;
public List<List<Integer>> permute(int[] nums) {
used = new boolean[nums.length];// 标记数组
backtrack(nums,0);
return res;
}
public void backtrack(int[] nums, int startIndex){
if(path.size() == nums.length){
res.add(new ArrayList<>(path));
return;
}
// 因为全排列强调顺序,所以i从0开始遍历而组合从startIndex开始
for(int i = 0; i<nums.length; i++){
if(used[i]) continue; // path里已经收录的元素,直接跳过
path.add(nums[i]);
used[i] = true;
backtrack(nums,i+1);
// 回溯
path.removeLast();
// 回溯
used[i] = false;
}
}
}
47.全排列 II
链接: 参考讲解
这一题因为又前面的基础所以做的很快
如果数组中包含了重复数字那么需要考虑树层去重,如果是全排列的话也需要考虑树枝去重
class Solution {
List<List<Integer>> res = new ArrayList<>();
LinkedList<Integer> path = new LinkedList<>();
boolean[] used;
public List<List<Integer>> permuteUnique(int[] nums) {
used = new boolean[nums.length]; // 记录每个树枝上的数字
backtrack(nums,0);
return res;
}
public void backtrack(int[] nums, int startIndex){
if(path.size() == nums.length){
res.add(new ArrayList<>(path));
return;
}
HashSet<Integer> set = new HashSet<>(); // 记录每层的数字
for(int i=0; i<nums.length;i++){
// 如果这个数字在这一树枝上被用过则跳过
// 如果这一数字在这一层中被用过则跳过
if( used[i] || set.contains(nums[i])) continue;
set.add(nums[i]);
used[i] = true;
path.add(nums[i]);
backtrack(nums,i+1);
path.removeLast();
used[i] = false;
}
}
}
重点看: 树枝去重和树层去重的区别