代码随想录算法训练营第二十八天|LeetCode491,46,47
491.递增子序列(*)
看到这个题,与前面那道题相比,再去重的基础上,又多了几个条件:一是子集必须递增的,子集中至少有两个元素,且两个整数相等被视作递增序列的一种特殊情况。
需要注意的一点,这个题是找子序列,而不是找子集,所以不能像前面两道题一样对数组进行排序。所以这个题的去重逻辑与前面几个的去重不一样。
这里采用HashSet来进行去重,每次个单次循环新建一个HashSet来判断每一树层有无重复。
List<List<Integer>> result = new ArrayList<>();
List<Integer> path = new ArrayList<>();
public void backTracking(int[] nums, int startIndex){
//这个条件其实没必要
if (startIndex >= nums.length){
return;
}
//终止条件
if (path.size()>=2){
result.add(new ArrayList<>(path));
}
//取子序列,而不是子集,因此去重逻辑不能与前面几个题一样。
HashSet<Integer> uset = new HashSet<>();
for (int i = startIndex; i<nums.length;i++){
//前面的条件判断同一树枝上是否满足递增。后面判断同一树层上该值是否出现过。
if (!path.isEmpty() && nums[i] < path.get(path.size()-1)||uset.contains(nums[i])){
continue;
}
uset.add(nums[i]);
path.add(nums[i]);
backTracking(nums,i+1);
path.remove(path.size()-1);
}
}
public List<List<Integer>> findSubsequences(int[] nums) {
backTracking(nums,0);
return result;
}
46.全排列
首先排列是有序的,也就是说 [1,2] 和 [2,1] 是两个集合,这和之前分析的子集以及组合所不同的地方。
可以看出元素1在[1,2]中已经使用过了,但是在[2,1]中还要在使用一次1,所以处理排列问题就不用使用startIndex了。
但排列问题需要一个used数组,标记已经选择的元素,一个排列里一个元素只能使用一次。
List<List<Integer>> result = new ArrayList<>();
List<Integer> path = new ArrayList<>();
public void backTracking(int[] nums, int[] used){
if (path.size() == nums.length){
result.add(new ArrayList<>(path));
return;
}
for (int i = 0;i<nums.length;i++){
if (used[i] == 1){
continue;
}
path.add(nums[i]);
used[i] = 1;
backTracking(nums,used);
path.remove(path.size()-1);
used[i] = 0;
}
}
public List<List<Integer>> permute(int[] nums) {
int[] used = new int[nums.length];
Arrays.fill(used,0);
backTracking(nums,used);
return result;
}
47.全排列 II
这个题还是经典的去重,同样同一个树枝上可以重复,但是同一树层上可以重复的,因此,跟那个组合之和类似。
List<List<Integer>> result = new ArrayList<>();
List<Integer> path = new ArrayList<>();
public void backTracking(int[] nums, int[] used){
if (path.size() == nums.length){
result.add(new ArrayList<>(path));
return;
}
HashSet<Integer> level = new HashSet<>();
for (int i = 0; i<nums.length;i++){
//同一树枝上判断这个值是不是已经被用过了
if (used[i] == 1){
continue;
}
//同一树层上,去重
if (level.contains(nums[i])){
continue;
}
path.add(nums[i]);
used[i] = 1;
level.add(nums[i]);
backTracking(nums,used);
path.remove(path.size()-1);
used[i] = 0;
}
}
public List<List<Integer>> permuteUnique(int[] nums) {
int[] used = new int[nums.length];
Arrays.fill(used, 0);
backTracking(nums,used);
return result;
}