算法训练Day29|* 491.递增子序列* 46.全排列* 47.全排列 II

简介: 算法训练Day29|* 491.递增子序列* 46.全排列* 47.全排列 II

LeetCode:491.递增子序列

491. 递增子序列 - 力扣(LeetCode)


1.思路:

创建两个全局变量,一个path收集符合条件的结果,另一个result收集所有符合条件的结果。

当path.size>=2时,符合条件:数量大于1,即刻加入result结果集中。

HashSet临时集合存储所有遍历过的元素,调用hs.contains()方法用于同一递归深度的树层去重!!!

for循环横向遍历实现广度搜索。


2.代码实现:

 1class Solution {
 2    List<List<Integer>> result = new ArrayList<>(); // 创建收集结果的结果集
 3    List<Integer> path = new ArrayList<>(); // 收集每个结果
 4    public List<List<Integer>> findSubsequences(int[] nums) {
 5        backtracking(nums, 0); // 回溯函数
 6        return result; // 返回结果集
 7    }
 8    public void backtracking(int[] nums, int startIndex) {
 9        if (path.size() > 1) { // 单个结果集的长度大于1时,即刻加入到结果集中
10            result.add(new ArrayList<>(path));
11        }
12        HashSet<Integer> hs = new HashSet<>(); // 临时的结合hs,用于树层去重
13        for (int i = startIndex; i < nums.length; i++) {
14            if (!path.isEmpty() && path.get(path.size() - 1) > nums[i] || hs.contains(nums[i])) { // 什么时候去重?树层元素相同时,①路径元素不为空且path中最后一个数值大于当前nums[i] ②同一深度的树层包含同个元素时去重
15                continue;
16            }
17            hs.add(nums[i]); // 收集所有遍历的元素
18            path.add(nums[i]); // 符合条件的元素加入路径中
19            backtracking(nums, i + 1); // 回溯函数继续深度遍历添加符合条件的元素
20            path.remove(path.size() - 1);  // 回溯:结束本层回溯函数,返回上一层继续
21        }
22    }
23}

3.复杂度分析:

时间复杂度:一个元素在回溯一层同时进行for循环和调用递归函数时间耗费为2倍,n层位2^n;n个元素则复杂度为O(n*2^n).

空间复杂度:栈堆空间开销,递归函数消耗栈,层数最大为N,此时时间复杂度为O(n).堆空间开销为集合O(n)。则整体为O(n).


LeetCode:46.全排列

46. 全排列 - 力扣(LeetCode)


1.思路:

回溯函数不用传入startIndex来限定位置了,直接循环遍历即可,当长度和数组长度相同时加入到结果集中。终止条件:直到path中出现相同元素结束本层循环,继续下一次循环。(终止条件为什么不能是path.size()>nums.length??)


2.代码实现:

 1//实现一:
 2class Solution {
 3    List<List<Integer>> result = new ArrayList<>();
 4    List<Integer> path = new ArrayList<>();
 5    public List<List<Integer>> permute(int[] nums) {
 6        backtracking(nums);
 7        return result;
 8    }
 9    public void backtracking(int[] nums) {
10        if (path.size() == nums.length) {
11            result.add(new ArrayList<>(path));
12        }
13        for (int i = 0; i < nums.length; i++) {
14            if (path.contains(nums[i])) {
15                continue;
16            }
17            path.add(nums[i]);
18            backtracking(nums);
19            path.remove(path.get(path.size() - 1));
20        }
21    }
22}

实现2

 1class Solution {
 2    List<List<Integer>> result = new ArrayList<>();
 3    LinkedList<Integer> path = new LinkedList<>();
 4    public List<List<Integer>> permute(int[] nums) {
 5        // if (num)
 6        backtracking(nums, path);
 7        return result;
 8    }
 9    public void backtracking(int[] nums, LinkedList<Integer> path) {
10        if (path.size() == nums.length) {
11            result.add(new ArrayList<>(path));
12        }
13        for (int i = 0; i < nums.length; i++) {
14            if (path.contains(nums[i])) { // 终止条件
15                continue;
16            }
17            path.add(nums[i]);
18            backtracking(nums, path);
19            path.removeLast();
20        }
21    }
22}

3.复杂度分析:

时间复杂度:一次遍历为n,n次遍历为n^2.为什么代码随想录给的是O(n!).

空间复杂度:栈开销O(n).堆开销为O(n).

LeetCode:47.全排列 II

47. 全排列 II - 力扣(LeetCode)

1.思路:

2.代码实现:

 1class Solution {
 2    List<List<Integer>> result = new ArrayList<>(); // 存储结果的结果集
 3    List<Integer> path = new ArrayList<>(); // 收集每个符合条件的结果
 4    public List<List<Integer>> permuteUnique(int[] nums) {
 5        boolean[] used = new boolean[nums.length]; // used[]做标记
 6        Arrays.fill(used, false); // 全部赋予false
 7        Arrays.sort(nums); // 排序,便于剪枝(优化搜索)
 8        backtracking(nums, used); // 回溯函数
 9        return result; // 返回结果集
10    }
11    public void backtracking(int[] nums, boolean[] used) {
12        if (path.size() == nums.length) { // 当临时收集的结果等于nums数组长度时,加入到结果集
13            result.add(new ArrayList<>(path)); 
14            return; // 返回上一层
15        }
16        // 横向遍历 
17        for (int i = 0; i < nums.length; i++) {
18            if (i > 0 && nums[i] == nums[i - 1] && used[i - 1] == false) { // 树层去重
19                continue;
20            }
21            if (used[i] == false) { // 没有遍历过 才进行加入操作
22                used[i] = true; // 置为true表明没有遍历过
23                path.add(nums[i]); // 加入到结果中
24                backtracking(nums, used); // 回溯函数,计息递归
25                path.remove(path.size() - 1); // 去重
26                used[i] = false; //从一下数开始,当前数置为false
27            }
28        }
29    }
30}

3.复杂度分析:

时间复杂度:O(n2^n).有疑问:代码随想录O(n!n).

空间复杂度:O(n).


相关文章
|
6天前
|
算法 C++ 索引
【算法】——全排列算法讲解
【算法】——全排列算法讲解
|
6天前
|
机器学习/深度学习 存储 算法
【算法训练-回溯算法 一】【排列问题】全排列、全排列II
【算法训练-回溯算法 一】【排列问题】全排列、全排列II
52 0
|
9月前
|
算法
算法修炼Day52|● 300.最长递增子序列 ● 674. 最长连续递增序列 ● 718. 最长重复子数组
算法修炼Day52|● 300.最长递增子序列 ● 674. 最长连续递增序列 ● 718. 最长重复子数组
|
6天前
|
算法 Java
算法-----全排列
算法-----全排列
|
6月前
|
算法
代码随想录算法训练营第五十二天 | LeetCode 300. 最长递增子序列、674. 最长连续递增序列、718. 最长重复子数组
代码随想录算法训练营第五十二天 | LeetCode 300. 最长递增子序列、674. 最长连续递增序列、718. 最长重复子数组
39 1
|
6月前
|
算法
代码随想录算法训练营第二十八天 | LeetCode 491. 递增子序列、46. 全排列、47. 全排列 II
代码随想录算法训练营第二十八天 | LeetCode 491. 递增子序列、46. 全排列、47. 全排列 II
40 0
|
11月前
|
自然语言处理 算法
经典算法之——解决全排列问题以及详解
经典算法之——解决全排列问题以及详解
187 0
|
11月前
|
机器学习/深度学习 算法 Python
Python|“套娃”算法-递归算法解决全排列
Python|“套娃”算法-递归算法解决全排列
95 0
|
11月前
|
存储 算法 前端开发
前端算法-最长的递增子序列
前端算法-最长的递增子序列
|
12月前
|
算法
回溯算法 全排列模板
回溯算法 全排列模板
54 0