491.递增子序列
文章链接:代码随想录 (programmercarl.com)
思路:无思路
看完文章后的反思:
(1)跟子集问题一样,我们需要在每个节点就收获结果,因此无需return
(2)一般来说去重是要先对数组进行排序,但是此题不能排序,这样会改变递增子序列
(3)通过画图可知,应当在树层上去重,但是此题有个注意点,每个树层都要新建一个used数组,从而对本层进行去重
(4)不能回头,所以要用startIndex控制循环开始的位置
Java代码:
class Solution {
//定义全局变量
List<List<Integer>> result = new ArrayList<>();
List<Integer> path = new ArrayList<>();
public List<List<Integer>> findSubsequences(int[] nums) {
help(nums,0);
return result;
}
private void help(int[] nums,int startIndex){
//每一次递归函数的开始,就是进入节点时候,这个时候就要开始收获结果
if(path.size() > 1){
result.add(new ArrayList<>(path));
}
//子集问题不需要写终止条件,因为startIndex一直在++
Set<Integer> myset = new HashSet<>();//set集合用来判断每个树层是否取到重复的元素
//确定单层逻辑
for(int i = startIndex;i < nums.length;i++){
//去重:是否重复;判断是否递增
if(path.size() >= 1 && nums[i] < path.get(path.size() - 1) || myset.contains(nums[i])){
continue;
}
path.add(nums[i]);
myset.add(nums[i]);
//递归
help(nums,i + 1);
//回溯
path.remove(path.size() - 1);
//为什么不用回溯myset呢,因为myset是在每次树层遍历时创建一个,它每次都只针对树层
}
}
}
46.全排列
文章链接:代码随想录 (programmercarl.com)
思路:
(1)排列有顺序,所以【1,2】和【2,1】是不同的集合,因此每次都要完整遍历nums,无需startIndex
(2)题目说明了是无重复元素,因此无需去重
(3)需要used数组告诉for循环这个元素是否已经取了
Java代码:
class Solution {
List<List<Integer>> result = new ArrayList<>();
List<Integer> path = new ArrayList<>();
public List<List<Integer>> permute(int[] nums) {
boolean[] used = new boolean[nums.length];
Arrays.fill(used,false);
backtracing(nums,used);
return result;
}
private void backtracing(int[] nums,boolean[] used){
//(2)收获结果
if(path.size() == nums.length){
result.add(new ArrayList<>(path));
return;
}
//(3)处理逻辑
for(int i = 0; i < nums.length;i++){
//如果nums[i]被使用了,就直接遍历下一个元素
if(used[i]){
continue;
}
path.add(nums[i]);
used[i] = true;
backtracing(nums,used);
used[i] = false;
path.remove(path.size() - 1);
}
}
}
47.全排列||
文章链接:代码随想录 (programmercarl.com)
思路:该题明确了数组中会有重复的元素,因此需要考虑去重
(1)通过画图,可以发现是要在树层上去重,利用used数组,used[i-1](是看前一个元素) == false表示重复
(2)涉及到去重的话,需要对数组进行排序
反思:
又忘记要对数组进行排序!!!
Java代码:
class Solution {
List<List<Integer>> result = new ArrayList<>();
List<Integer> path = new ArrayList<>();
public List<List<Integer>> permuteUnique(int[] nums) {
if(nums.length == 0){
return result;
}
boolean[] used = new boolean[nums.length];
Arrays.fill(used,false);
Arrays.sort(nums);
backtracing(nums,used);
return result;
}
private void backtracing(int[] nums,boolean[] used){
//(2)终止条件,收获结果
if(path.size() == nums.length){
result.add(new ArrayList<>(path));
return;
}
//(3)确定单层逻辑
for(int i = 0; i < nums.length;i++){
//去重(一定要先对nums数组进行排序)
if(i > 0 && nums[i] == nums[i - 1] && used[i-1] == false){
continue;
}
//告诉for循环如何选择数据
if(used[i]==true){
continue;
}
path.add(nums[i]);
used[i] = true;
backtracing(nums,used);
used[i] = false;
path.remove(path.size() - 1);
}
}
}