自学内容网 自学内容网

Day 25

491.递增子序列

力扣题目链接(opens new window)

给定一个整型数组, 你的任务是找到所有该数组的递增子序列,递增子序列的长度至少是2。
示例:

  • 输入: [4, 6, 7, 7]
  • 输出: [[4, 6], [4, 7], [4, 6, 7], [4, 6, 7, 7], [6, 7], [6, 7, 7], [7,7], [4,7,7]]

说明:

  • 给定数组的长度不会超过15。
  • 数组中的整数范围是 [-100,100]
  • 给定数组中可能包含重复数字,相等的数字应该被视为递增的一种情况。

思考与分析

思路梳理

首先,这个题目和之前的去重题目有些相似。但注意在子集问题里需要先对数组进行排序,方便标记是否重复。但是在这个题目中,数组不能够先进行排序。这个可以用哈希来确定当前数字是否在之前已经存在了,可以选择 set

使用数组作为哈希表,能够进行进一步的优化

在终止条件判断时,要注意最终要取的结果长度至少为 2。

回溯三步走

1、参数、返回值
全局参数:path 一维数组、res 二维数组
参数:nums 给出的数组、startindex

一个元素不能够重复使用,需要 startindex,调整下一层递归的位置

2、终止条件
结果长度大小至少为 2

3、单层逻辑
unordered_set<int> uset; 是记录本层元素是否重复使用,新的一层uset都会重新定义(清空),所以要知道uset只负责本层!
image.png|600

题解

class Solution {
private:
    vector<vector<int>> result;
    vector<int> path;
    void backtracking(vector<int>& nums, int startIndex) {
        if (path.size() > 1) {
            result.push_back(path);
        }
        unordered_set<int> uset; 
        for (int i = startIndex; i < nums.size(); i++) {
            if ((!path.empty() && nums[i] < path.back())
                    || uset.find(nums[i]) != uset.end()) {
                    continue;
            }
            uset.insert(nums[i]); 
            path.push_back(nums[i]);
            backtracking(nums, i + 1);
            path.pop_back();
        }
    }
public:
    vector<vector<int>> findSubsequences(vector<int>& nums) {
        result.clear();
        path.clear();
        backtracking(nums, 0);
        return result;
    }
};

46.全排列

力扣题目链接(opens new window)

给定一个 没有重复 数字的序列,返回其所有可能的全排列。

示例:

  • 输入: [1,2,3]
  • 输出: [ [1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], [3,2,1] ]

思考与分析

思路梳理

相对于之前的组合问题,排列问题不需要 index,因为排序是有序的。
这一题目中,给定的序列是没有重复数字的。需要返回的是所有可能的全排列。
需要用到 used 数组标记元素是否选择过,因为一个排列中一个元素只能用一次。
image.png

排列问题的不同:

  • 每层都是从0开始搜索而不是startIndex
  • 需要used数组记录path里都放了哪些元素了

回溯三步走

1、参数、返回值
全局参数:path 一维数组、res 二维数组
参数:nums 给出的数组、used 数组

2、终止条件
也就是要取到叶子节点,也就是 path 的大小和 nums 的大小相等

3、单层逻辑
used数组,其实就是记录此时path里都有哪些元素使用了,一个排列里一个元素只能使用一次

题解

class Solution {
public:
    vector<vector<int>> result;
    vector<int> path;
    void backtracking (vector<int>& nums, vector<bool>& used) {
        if (path.size() == nums.size()) {
            result.push_back(path);
            return;
        }
        for (int i = 0; i < nums.size(); i++) {
            if (used[i] == true) continue; 
            used[i] = true;
            path.push_back(nums[i]);
            backtracking(nums, used);
            path.pop_back();
            used[i] = false;
        }
    }
    vector<vector<int>> permute(vector<int>& nums) {
        result.clear();
        path.clear();
        vector<bool> used(nums.size(), false);
        backtracking(nums, used);
        return result;
    }
};

47.全排列 II

力扣题目链接(opens new window)

给定一个可包含重复数字的序列 nums ,按任意顺序 返回所有不重复的全排列。

示例 1:

  • 输入:nums = [1,1,2]
  • 输出: [[1,1,2], [1,2,1], [2,1,1]]

示例 2:

  • 输入:nums = [1,2,3]
  • 输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]

提示:

  • 1 <= nums.length <= 8
  • -10 <= nums[i] <= 10

思考与分析

思路梳理

给定一个可包含重复数字的序列,要返回所有不重复的全排列
去重一定要对元素进行排序,这样我们才方便通过相邻的节点来判断是否重复使用了

对于自增子序列求解时,不能排序,要利用哈希表来去重

image.png|750
对同一树层,前一位(也就是nums[i-1])如果使用过,那么就进行去重。
组合问题和排列问题是在树形结构的叶子节点上收集结果,而子集问题就是取树上所有节点的结果

回溯三步走

1、参数、返回值
全局参数:path 一维数组、res 二维数组
参数:nums 给出的数组、used 数组

2、终止条件
也就是要取到叶子节点,也就是 path 的大小和 nums 的大小相等

3、单层逻辑
通过 used 数组来进行去重的操作

题解

class Solution {
private:
    vector<vector<int>> result;
    vector<int> path;
    void backtracking (vector<int>& nums, vector<bool>& used) {
        
        if (path.size() == nums.size()) {
            result.push_back(path);
            return;
        }
        for (int i = 0; i < nums.size(); i++) {
            if (i > 0 && nums[i] == nums[i - 1] && used[i - 1] == false) {
                continue;
            }
            if (used[i] == false) {
                used[i] = true;
                path.push_back(nums[i]);
                backtracking(nums, used);
                path.pop_back();
                used[i] = false;
            }
        }
    }
public:
    vector<vector<int>> permuteUnique(vector<int>& nums) {
        result.clear();
        path.clear();
        sort(nums.begin(), nums.end()); 
        vector<bool> used(nums.size(), false);
        backtracking(nums, used);
        return result;
    }
};

原文地址:https://blog.csdn.net/qq_74215116/article/details/144016247

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!