491.递增子序列
参考文章:代码随想录
参考视频:回溯算法精讲,树层去重与树枝去重 | LeetCode:491.递增子序列_哔哩哔哩_bilibili
解题思路:
用[4, 7, 6, 7]这个数组来举例,抽象为树形结构如图:
确定递归函数参数,参数为数组nums,for循环起始位置startIndex。
确定终止条件,当路径数组path的大小大于1时,将path添加到结果集中。
确定单层递归逻辑,由于结果中的子集要求是递增的,因此在for循环遍历中需要判断当前遍历的元素是大于或等于path中最后一个元素的。同时,因为在树枝中不能取同一元素,因此需要添加一个标记数组used用来记录已经用过的元素,当出现上述两种情况时则跳到下一层循环。
public class Leetcode491 {
List<List<Integer>> res = new ArrayList<>();
List<Integer> path = new ArrayList<>();
public List<List<Integer>> findSubsequences(int[] nums) {
track(nums,0);
return res;
}
public void track(int[] nums, int startIndex) {
if (path.size() > 1) {
res.add(new ArrayList<>(path));
}
Set<Integer> used = new HashSet<>();
for (int i = startIndex; i < nums.length; i++) {
if (!path.isEmpty() && nums[i] < path.get(path.size() - 1) || used.contains(nums[i])) {
continue;
}
used.add(nums[i]);
path.add(nums[i]);
track(nums,i+1);
path.remove(path.size()-1);
}
}
}
46.全排列
参考文章:代码随想录
参考视频:组合与排列的区别,回溯算法求解的时候,有何不同?| LeetCode:46.全排列_哔哩哔哩_bilibili
解题思路:
本题由于需要收集一个数组的全排列,因此在递归过程中需要用标记数组uesd记录已经使用过的元素。
以[1,2,3]为例,抽象成树形结构如下:
确定递归函数参数,传进来的数组nums以及标记数组used。
确定终止条件,当路径数组path的大小等于数组长度时,添加该路径到结果集。
确定单层递归逻辑,当used[ i ] 为true时,跳到下一循环,若没有用过,添加该元素到path中,将used[ i ] 改为true,进入到下一层递归,注意used和路径数组path的回溯。
public class Leetcode46 {
List<List<Integer>> res = new ArrayList<>();
List<Integer> path = new ArrayList<>();
public List<List<Integer>> permute(int[] nums) {
boolean[] used = new boolean[nums.length];
track(nums,used);
return res;
}
public void track(int[] nums, boolean[] used) {
if (path.size() == nums.length) {
res.add(new ArrayList<>(path));
}
for (int i = 0; i < nums.length; i++) {
if (used[i]) {
continue;
}
used[i] = true;
path.add(nums[i]);
track(nums, used);
path.remove(path.size() - 1);
used[i] = false;
}
}
}
47.全排列 II
参考文章:代码随想录
解题思路:
本题和上题的区别是传入的数组会出现重复的数字,因此在同一数层的情况下要注意去重。
我以示例中的 [1,1,2]为例 (为了方便举例,已经排序)抽象为一棵树,去重过程如图:
图中我们对同一树层,前一位(也就是nums[i-1])如果使用过,那么就进行去重。
确定递归函数参数,传入数组nums以及标记数组used。
确定终止条件,当路径数组path大小等于数组nums的长度时,将路径path添加到结果集中。
确定单层递归逻辑,当出现两种情况需要跳过该循环,i > 0 && nums[i] == nums[i - 1] && !used[i - 1],或者used[i] == true时。第一种是数层的去重,第二种是树枝递归中不能使用相同的元素。
public class Leetcode47 {
List<List<Integer>> res = new ArrayList<>();
List<Integer> path = new ArrayList<>();
public List<List<Integer>> permuteUnique(int[] nums) {
Arrays.sort(nums);
boolean[] used = new boolean[nums.length];
track(nums, used);
return res;
}
public void track(int[] nums, boolean[] used) {
if (path.size() == nums.length) {
res.add(new ArrayList<>(path));
return;
}
for (int i = 0; i < nums.length; i++) {
if (i > 0 && nums[i] == nums[i - 1] && !used[i - 1]||used[i]) {
continue;
}
used[i] = true;
path.add(nums[i]);
track(nums, used);
used[i] = false;
path.remove(path.size() - 1);
}
}
}