[豪の算法奇妙冒险] 代码随想录算法训练营第二十五天 | 491-递增子序列、46-全排列、47-全排列Ⅱ
代码随想录算法训练营第二十五天 | 491-递增子序列、46-全排列、47-全排列Ⅱ
LeetCode491 递增子序列
题目链接:https://leetcode.cn/problems/non-decreasing-subsequences/description/
文章讲解:https://programmercarl.com/0491.递增子序列.html
视频讲解:https://www.bilibili.com/video/BV1EG4y1h78v/?vd_source=b989f2b109eb3b17e8178154a7de7a51
本题求子序列,很明显一个元素不能重复使用,所以需要startIndex,调整下一层递归的起始位置
同一父节点下的同层上使用过的元素就不能再使用了,所以要进行树层去重。这里使用HashSet实现树层去重,add后不用再remove,因为它是记录本层元素是否重复使用,新的一层的HashSet都会重新定义(清空),它只负责本层

class Solution {
List<List<Integer>> result = new ArrayList<>();
List<Integer> records = new ArrayList<>();
public List<List<Integer>> findSubsequences(int[] nums) {
backTracking(nums, 0, -100);
return result;
}
public void backTracking(int[] nums, int start, int tailNum){
if(records.size() >= 2){
result.add(new ArrayList<>(records));
}
HashSet<Integer> used = new HashSet<>();
for(int i = start; i < nums.length; i++){
if((!records.isEmpty() && records.get(records.size()-1) > nums[i]) || used.contains(nums[i])){
continue;
}
records.add(nums[i]);
used.add(nums[i]);
backTracking(nums, i+1, nums[i]);
records.remove(records.size()-1);
}
}
}
LeetCode46 全排列
题目链接:https://leetcode.cn/problems/permutations/description/
文章讲解:https://programmercarl.com/0046.全排列.html
视频讲解:https://www.bilibili.com/video/BV19v4y1S79W/?vd_source=b989f2b109eb3b17e8178154a7de7a51
首先,排列是有序的,也就是说 [1,2] 和 [2,1] 是两个集合,这和之前的子集问题以及组合问题不同。可以看出,元素1在[1,2]中已经使用过了,但是在[2,1]中还要在使用一次1,所以处理排列问题时就不用使用startIndex了
一个排列里一个元素只能使用一次,所以还需要使用一个used数组,用来标记已经选择的元素,防止重复选择

class Solution {
List<List<Integer>> result = new ArrayList<>();
List<Integer> records = new ArrayList<>();
public List<List<Integer>> permute(int[] nums) {
boolean[] used = new boolean[nums.length];
backTracking(nums, used);
return result;
}
public void backTracking(int[] nums, boolean[] used){
if(records.size() == nums.length){
result.add(new ArrayList<>(records));
return;
}
for(int i = 0; i < nums.length; i++){
if(used[i]){
continue;
}
records.add(nums[i]);
used[i] = true;
backTracking(nums, used);
used[i] = false;
records.remove(records.size()-1);
}
}
}
LeetCode47 全排列Ⅱ
题目链接:https://leetcode.cn/problems/permutations-ii/description/
文章讲解:https://programmercarl.com/0047.全排列II.html
视频讲解:https://www.bilibili.com/video/BV1R84y1i7Tm/?vd_source=b989f2b109eb3b17e8178154a7de7a51
这道题目和 LeetCode46 全排列 的区别在与给定一个可包含重复数字的序列,要返回所有不重复的全排列,意味着需要树层去重
同一父节点下的同层上使用过的元素就不能再使用了,所以要进行树层去重。这里使用HashSet实现树层去重,add后不用再remove,因为它是记录本层元素是否重复使用,新的一层的HashSet都会重新定义(清空),它只负责本层

class Solution {
List<List<Integer>> result = new ArrayList<>();
List<Integer> records = new ArrayList<>();
public List<List<Integer>> permuteUnique(int[] nums) {
boolean[] used = new boolean[nums.length];
backTracking(nums, used);
return result;
}
public void backTracking(int[] nums, boolean[] used){
if(records.size() == nums.length){
result.add(new ArrayList<>(records));
return;
}
HashSet<Integer> hash = new HashSet<>();
for(int i = 0; i < nums.length; i++){
if(used[i] || hash.contains(nums[i])){
continue;
}
records.add(nums[i]);
used[i] = true;
hash.add(nums[i]);
backTracking(nums, used);
used[i] = false;
records.remove(records.size()-1);
}
}
}

浙公网安备 33010602011771号