DAY28 491. 递增子序列 + 46. 全排列 + 47. 全排列 II

491. 递增子序列

题目要求:给定一个整型数组, 你的任务是找到所有该数组的递增子序列,递增子序列的长度至少是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]。
  • 给定数组中可能包含重复数字,相等的数字应该被视为递增的一种情况。

思路

先排序,然后抽象成一棵树,注意相等的数字被视为递增的一种情况。

本题目不能够排序了,去重逻辑改变了。

  • 单层搜索逻辑

在图中可以看出,同一父节点下的同层上使用过的元素就不能再使用了

这也是需要注意的点,unordered_set uset; 是记录本层元素是否重复使用,新的一层uset都会重新定义(清空),所以要知道uset只负责本层!

class Solution {
public:
    vector path;
    vector> res;
    void backtracking(const vector& nums, int startIndex) {
        if (path.size() >= 2) res.push_back(path);
        if (startIndex > nums.size()) return;
        unordered_set 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();
        }
    }
    vector> findSubsequences(vector& nums) {
        path.clear();
        res.clear();
        backtracking(nums, 0);
        return res;
    }
};

46. 全排列

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

示例:

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

思路

抽象过后发现,本题变成了同一个树枝上不能有相同的元素。依然可以用used数组进行统计。

用过的数字用continue跳过,否则会陷入死循环。

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

47. 全排列 II

题目要求:给定一个可包含重复数字的序列 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

在上一题的基础上加上对nums的排列,把相同的元素聚集在一起。然后再加上判断同层不能重复的规则,用一个used数组能够同时完成对同层(前一个是false代表同一层使用过)和同树枝(前一个是true代表同一个树枝使用过)的判断。

class Solution {
public:
    vector path;
    vector> res;
    void backtracking(const vector& nums, vector used) {
        if (path.size() == nums.size()) {
            res.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] == true) continue;
            path.push_back(nums[i]);
            used[i] = true;
            backtracking(nums, used);
            used[i] = false;
            path.pop_back();
        }
    }
    vector> permuteUnique(vector& nums) {
        res.clear();
        path.clear();
        vector used(nums.size(), false);
        sort(nums.begin(), nums.end());
        backtracking(nums, used);
        return res;
    }
};

你可能感兴趣的:(算法,数据结构)