46. 全排列
题目链接:46. 全排列
思路:
全排列和子集/组合问题的区别在于,对于子集/组合问题来说,start向前移动之后,start之前的内容不会再用到,但是全排列会用到。需要额外使用 used 数组来标记哪些元素还可以被选择。used 数组标记已经在路径上的元素避免重复选择,然后收集所有叶子节点上的值,就是所有全排列的结果。
class Solution {
LinkedList<Integer> track = new LinkedList<>();
List<List<Integer>> res = new LinkedList<>();
boolean[] used;
public List<List<Integer>> permute(int[] nums) {
used = new boolean[nums.length];
backtrack(nums);
return res;
}
void backtrack(int[] nums) {
if (track.size() == nums.length) {
res.add(new LinkedList<>(track));
return;
}
for (int i = 0; i < nums.length; i++) {
if (used[i]) {
continue;
}
track.add(nums[i]);
used[i] = true;
backtrack(nums);
track.removeLast();
used[i] = false;
}
}
}
47. 全排列 II
题目链接:47. 全排列 II
思路:
保证相同元素在排列中的相对位置保持不变。比如说 nums = [1,2,2'] 这个例子,保持排列中 2 一直在 2' 前面。
class Solution {
List<List<Integer>> res = new LinkedList<>();
// 记录回溯算法的递归路径
LinkedList<Integer> track = new LinkedList<>();
// track 中的元素会被标记为 true
boolean[] used;
public List<List<Integer>> permuteUnique(int[] nums) {
Arrays.sort(nums);
used = new boolean[nums.length];
backtrack(nums);
return res;
}
void backtrack(int[] nums) {
if (track.size() == nums.length) {
res.add(new LinkedList<>(track));
return;
}
for (int i = 0; i < nums.length; i++) {
if (used[i]) {
continue;
}
if (i > 0 && nums[i - 1] == nums[i] && !used[i - 1]) {
continue;
}
track.add(nums[i]);
used[i] = true;
backtrack(nums);
track.removeLast();
used[i] = false;
}
}
}
491. 递增子序列
题目链接:491. 递增子序列
思路: 这题看上去很像子集问题,但是有很大区别。在子集问题中,我们通过排序数组再加一个标记数组来来避免重复。但对于这题,如果先排列数组,那么数组直接就变成递增的了。通过画树可以看出,同一父节点下的同层上使用过的元素就不能在使用了,因此可以使用一个set来存储已经用过的数字。注意在收集结果的位置,不要return,因为要取树上的所有节点。
class Solution {
LinkedList<Integer> track = new LinkedList<>();
List<List<Integer>> res = new LinkedList<>();
public List<List<Integer>> findSubsequences(int[] nums) {
backtrack(nums, 0);
return res;
}
void backtrack(int[] nums, int start) {
if (track.size() >= 2) {
res.add(new LinkedList<>(track));
// 注意这里不要加return,因为要取树上的所有节点
}
HashSet<Integer> used = new HashSet<>();
for (int i = start; i < nums.length; i++) {
if (!track.isEmpty() && track.getLast() > nums[i]) {
continue;
}
if (used.contains(nums[i])) {
continue;
}
used.add(nums[i]);
track.add(nums[i]);
backtrack(nums, i + 1);
track.removeLast();
}
}
}