491. Non-decreasing Subsequences
Given an integer array nums, return all the different possible non-decreasing subsequences of the given array with at least two elements. You may return the answer in any order.
题目解析:
- 求递增序列,所以不能排序,从而不能只比较前一个,而是要比较之前所有是否出现过
代码:
class Solution {
List<List<Integer>> result = new ArrayList<>();
public List<List<Integer>> findSubsequences(int[] nums) {
backtracking(nums, 0, new ArrayList<>());
return result;
}
public void backtracking(int[] nums, int start, List<Integer> comb) {
if (comb.size() >=2) {
result.add(new ArrayList<>(comb));
}
Set<Integer> set = new HashSet<>();
for (int i = start; i < nums.length; i++) {
if (set.contains(nums[i])) continue;
set.add(nums[i]);
// if (i > start && nums[i] == nums[i-1]) continue;
if (comb.isEmpty() || nums[i] >= comb.get(comb.size()-1)) {
comb.add(nums[i]);
backtracking(nums, i + 1, comb);
comb.remove(comb.size() - 1);
}
}
}
}
46. Permutations
Given an array nums of distinct integers, return all the possible permutations. You can return the answer in any order.
题目解析:
- 排列需要考虑顺序
代码:
class Solution {
List<List<Integer>> result = new ArrayList<>();
public List<List<Integer>> permute(int[] nums) {
backtracking(nums, new ArrayList<>());
return result;
}
public void backtracking(int[] nums, List<Integer> path) {
if (path.size() == nums.length) {
result.add(new ArrayList<>(path));
return;
}
for (int i = 0; i < nums.length; i++) {
if (!path.contains(nums[i])){
path.add(nums[i]);
backtracking(nums, path);
path.remove(path.size() - 1);
}
}
}
}
47. Permutations II
Given a collection of numbers, nums, that might contain duplicates, return all possible unique permutations in any order.
题目解析:
- 为了记录元素是否已经使用,可以使用一个布尔数组存储,或者通过存储下标index来判断,之后在转化成具体值
- 因为存在重复元素,所以同样需要使用一个set记录在同一个位置是否使用过相同值的元素,如果有,则需跳过
代码:
class Solution {
List<List<Integer>> result = new ArrayList<>();
public List<List<Integer>> permuteUnique(int[] nums) {
boolean[] used = new boolean[nums.length];
backtracking(nums, new ArrayList<>(), used);
return result;
}
public void backtracking(int[] nums, List<Integer> path, boolean[] used) {
if (path.size() == nums.length) {
// List<Integer> comb = path.stream().map(i -> nums[i]).collect(Collectors.toList());
result.add(new ArrayList<>(path));
return;
}
Set<Integer> set = new HashSet<>();
for (int i = 0; i < nums.length; i++) {
if (!used[i] && !set.contains(nums[i])) {
set.add(nums[i]);
used[i] = true;
path.add(nums[i]);
backtracking(nums, path, used);
path.remove(path.size() - 1);
used[i] = false;
}
}
}
}
总结
对于排列问题,因为不同的顺序代表不同的排列,所以每次循环需要从0开始
- 一个元素不能使用两次,如果有值重复的元素,可以通过下标来区分,比如定义一个boolean数组来存储是否使用
- 如果有值重复元素,为了避免重复,同一个位置,不能使用值相同的元素(下标不同):
- 如果原数组可以排序,则需要在for循环中比较前一个元素是否与当前元素一样
- 如果原数组不可以排序,则需要定义一个set来判断是否之前出现过