491.递增子序列
给你一个整数数组
nums,找出并返回所有该数组中不同的递增子序列,递增子序列中 至少有两个元素 。你可以按 任意顺序 返回答案。数组中可能含有重复元素,如出现两个整数相等,也可以视作递增序列的一种特殊情况。 提示:
1 <= nums.length <= 15-100 <= nums[i] <= 100
思路
- 使用
path记录当前构建的递增子序列的元素 - 使用
map来记录当前层某个元素是否已使用过了,因为同一层相同元素递归遍历产生相同的结果,因此同一层中,一个数字只能继续递归遍历一次。
代码
class Solution {
public List<List<Integer>> findSubsequences(int[] nums) {
List<Integer> path = new ArrayList<>();
List<List<Integer>> res = new ArrayList<>();
if(nums.length < 2){
return res;
}
backTracking(nums, 0, path, res);
return res;
}
private void backTracking(int[] nums, int startIndex, List<Integer> path, List<List<Integer>> res){
if(startIndex == nums.length){
return;
}
boolean[] map = new boolean[201];
for(int i = startIndex; i < nums.length;i++){
// 当前元素与path不形成递增
if(path.size() > 0 && path.get(path.size() - 1) > nums[i]){
continue;
}
// map记录本层是否某个数字是否有使用过
// 去重
if(map[nums[i] + 100]){
continue;
}
path.add(nums[i]);
map[nums[i] + 100] = true;
if(path.size() >= 2){
res.add(List.copyOf(path));
}
backTracking(nums, i + 1, path, res);
path.remove(path.size() - 1);
}
}
}
46.全排列
给定一个不含重复数字的数组
nums,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。
思路
- 本题需要对数组元素的任意排列方式进行枚举,使用回溯法。
- 枚举时需要判断当前数组中哪些元素已经被使用了,创建与数组相同长度的
boolean类型数组isUsed。对于下标i,使用isUsed[i]标识nums[i]是否已被使用。
代码
class Solution {
public List<List<Integer>> permute(int[] nums) {
boolean[] isUsed = new boolean[nums.length];
List<Integer> path = new ArrayList<>();
List<List<Integer>> res = new ArrayList<>();
backTracking(nums, isUsed, path, res);
return res;
}
private void backTracking(int[] nums, boolean[] isUsed, List<Integer> path, List<List<Integer>> res){
if(path.size() == nums.length){
res.add(List.copyOf(path));
return;
}
for(int i = 0; i < nums.length; i++){
if(isUsed[i]){
continue;
}
isUsed[i] = true;
path.add(nums[i]);
backTracking(nums, isUsed, path, res);
path.remove(path.size() - 1);
isUsed[i] = false;
}
}
}
47.全排列 II
给定一个可包含重复数字的序列
nums,按任意顺序 返回所有不重复的全排列。提示:
- 1 <= nums.length <= 8
- 10 <= nums[i] <= 10
思路
与 46.全排列 相比,本题的区别是数组的元素是可重复的,因此多了一个去重的要求。
对于可重复元素的数组去重问题,可以参考40.组合总和II的方法,即在回溯树的每一层,设置一个map记录本层已取过的值,当再次遇到这个值时,跳过本轮操作,从而避免出现重复的结果。
代码
class Solution {
public List<List<Integer>> permuteUnique(int[] nums) {
boolean[] isUsed = new boolean[nums.length];
List<Integer> path = new ArrayList<>();
List<List<Integer>> res = new ArrayList<>();
backTracking(nums, isUsed, path, res);
return res;
}
private void backTracking(int[] nums, boolean[] isUsed, List<Integer> path, List<List<Integer>> res){
if(path.size() == nums.length){
res.add(List.copyOf(path));
return;
}
boolean[] map = new boolean[21];
for(int i = 0; i < nums.length; i++){
if(isUsed[i] || map[nums[i] + 10]){
continue;
}
map[nums[i] + 10] = true;
isUsed[i] = true;
path.add(nums[i]);
backTracking(nums, isUsed, path, res);
path.remove(path.size() - 1);
isUsed[i] = false;
}
}
}