2023.4.12 递增子序列
这道题既不是所有节点,也不是所有叶子结点,如何确定终止条件?
其实还是全部节点,我们只需要对加入结果集的元素进行筛选就行了
题目给出序列并不是一个递增的序列,只是给的例子是递增的,这需要我们在实际中去判断它是否是递增的。
此外,关于去重处理,由于本题是不能对其进行排序处理的,所以我们需要使用哈希表来进行去重的操作
几个关键点:
1.实际上本题还是遍历的所有节点,并不只是叶子结点,因此不需要return处理,但是我们的节点也是有要求的,必须长度大于等于2,这一点可以使用条件判断来处理加入结果集的数据。
2.题目给出的序列例子是递增的,但是实际并没有说明全部算例是递增的,所以还需要我们对加入结果的数据进行递增的判断
3.此题可能会出现重复的元素,但是它并不能排序,显然不能靠之前我们的排序去重方法,这里只能依靠哈希表来进行去重
class Solution {
List<List<Integer>> res = new ArrayList<>();
LinkedList<Integer> path = new LinkedList<>();
public List<List<Integer>> findSubsequences(int[] nums) {
backTracking(nums,0);
return res;
}
public void backTracking(int[] nums,int start){
//只有当path的长度大于2我们才将其放入结果集
if(path.size() >=2){
res.add(new ArrayList(path));
//因为是处理整个节点,我们不能设置return;
}
HashMap<Integer,Integer> hashMap = new HashMap<>();
for(int i = start;i<nums.length;i++){
//当前元素如果小于前一个元素,不能构成一个递增的子序列,因此需要继续循环,此外,在判断时,我们的path不能为空,否则会出现空指针异常
if(!path.isEmpty() && nums[i] < path.getLast()){
continue;
}
//如果当前数字在同一层被使用过,也不能继续使用
//每次进入backTracking,我们的hashMap就会重置,只有在同一层的for循环中,才会出现重复的情况。
if(hashMap.getOrDefault(nums[i],0) >= 1){
continue;
}
//正常处理逻辑
hashMap.put(nums[i],hashMap.getOrDefault(nums[i],0) + 1);
path.add(nums[i]);
backTracking(nums,i+1);
//回溯
path.removeLast();
}
}
}
2023.4.12 全排列
我们之前做过的都是组合问题,也就是对结果集的顺序是没有要求的,而排列则对我们的顺序有要求,也就是说,即使是相同的元素,位置不同也当做不同结果。
因此,对于我们的排列,我们已经不再需要设置初始下标start了,直接传入初始下标即可,但是需要注意,我们已经选择的元素不再需要重复选取,因此需要使用一个boolean数组来标记那些元素已经被选择了。
此外,这道全排列也是要求我们求叶子结点上的数据,因此终止条件需要加return
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];
backTracking(nums);
return res;
}
public void backTracking(int[] nums){
if(path.size() == nums.length){
res.add(new ArrayList(path));
return;
}
for(int i = 0;i<nums.length;i++){
if(used[i]){//当前元素被使用了
continue;
}
//正常逻辑
path.add(nums[i]);
used[i] = true;
backTracking(nums);
//回溯
path.removeLast();
used[i] = false;
}
}
}
2023.4.12 全排列Ⅱ
全排列的去重操作!
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];
Arrays.sort(nums);
backTracking(nums);
return res;
}
public void backTracking(int[] nums){
if(path.size() == nums.length){
res.add(new ArrayList(path));
return;
}
for(int i = 0;i<nums.length;i++){
if(used[i]){//全排列防止重复
continue;
}
if(i > 0 && nums[i] == nums[i-1] && used[i-1] == false){//去重
continue;
}
used[i] = true;
path.add(nums[i]);
backTracking(nums);
path.removeLast();
used[i] = false;
}
}
}
最关键的一步判断
i > 0 && nums[i] == nums[i-1] && used[i-1] == false
这个used[i-1] == false 是用来判断同一层的去重的,如果不加这个语句,会出现错误!
因此如果只有前面的语句的话,由于排列没有start索引,它会分不清这是同一层还是同一个树枝,导致在同一个树枝下出现重复元素也会导致去重处理,因此排列的去重需要格外注意。