[Leetcode] 491. Increasing Subsequences 解题报告

来源:互联网 发布:吹笛子软件 编辑:程序博客网 时间:2024/05/04 13:38

题目

Given an integer array, your task is to find all the different possible increasing subsequences of the given array, and the length of an increasing subsequence should be at least 2 .

Example:

Input: [4, 6, 7, 7]Output: [[4, 6], [4, 7], [4, 6, 7], [4, 6, 7, 7], [6, 7], [6, 7, 7], [7,7], [4,7,7]]

Note:

  1. The length of the given array will not exceed 15.
  2. The range of integer in the given array is [-100,100].
  3. The given array may contain duplicates, and two equal integers should also be considered as a special case of increasing sequence.

思路

1、DFS+backtracking:这是稍微有点变形的DFS题目:对于nums中的每个整数,如果符合条件,我们有两种选择:1)将它加入到结果中,然后进行DFS并且回溯;2)忽略它,直接进行DFS。为此我们在dfs的内部设立一个哈希表,表示已经尝试过的整数。这样对于具有重复整数的情况,比如例子中给出的[4, 6, 7, 7],当我们遇到第一个7之后,则包含7的所有升序组合都已经被输出了,那么当遇到第二个7的时候,我们就可以忽略。否则就生成重复结果了。

我发现DFS + BackTracking的题目往往有两种模板,一种是dfs中没有for循环的,也就是只调用DFS的下一层(有点像在dfs内部再进行dfs);另一种是dfs内含有从当前位置到末尾的for循环的,也就是在dfs内,平行的调用dfs(有点像dfs内部再进行一个bfs)。前一种模板适合无局部状态的情况,而后一种模板则比较适合需要记录局部状态的情况,例如本题目中我们需要记录已经采用过的整数。

2、前缀生成法:注意到一个升序序列总是可以由升序的前缀加上当前整数组成,所以我们可以采用递推的方式由升序的前缀生成所有的结果。例如对于本题目,我们初始的升序前缀是{},那么随着扫描的进行,结果的变化依次是:

当扫描到4之后,由升序前缀{{}}生成{4},然后升序前缀更新为{{}, {4}};

当扫描到6之后,由升序前缀{{}, {4}}生成{{6}, {4, 6}},然后升序前缀更新为{{}, {4}, {6}, {4, 6}};

当扫描到7之后,由升序前缀{{}, {4}, {6}, {4, 6}}生成{{7}, {4, 7}, {6, 7}, {4, 6, 7}},然后升序前缀更新为{{}, {4}, {6}, {4, 6}, {7}, {4, 7}, {6, 7}, {4, 6, 7}};

当再次扫描到7之后,由升序前缀{{}, {4}, {6}, {4, 6}, {7}, {4, 7}, {6, 7}, {4, 6, 7}}可以生成{{7}, {4, 7}, {6, 7}, {4, 6, 7}, {7, 7}, {4, 7, 7}, {6, 7, 7}, {4, 6, 7, 7}},然后升序前缀更新为{{}, {4}, {6}, {4, 6}, {7}, {4, 7}, {6, 7}, {4, 6, 7},{7}, {4, 7}, {6, 7}, {4, 6, 7}, {7, 7}, {4, 7, 7}, {6, 7, 7}, {4, 6, 7, 7}}。注意到背景为灰色的部分是重复元素,它们在set中将会被去重。最后再筛选出长度大于等于2的升序序列即可。

代码

1、DFS+backtracking:

class Solution {public:    vector<vector<int>> findSubsequences(vector<int>& nums) {        vector<vector<int>> ret;        vector<int> line;        dfs(nums, ret, line, 0);        return ret;    }private:    void dfs(vector<int> &nums, vector<vector<int>> &ret, vector<int> &line, int pos) {        if (line.size() > 1) {            ret.push_back(line);        }        unordered_set<int> hash;        for (int i = pos; i < nums.size(); ++i) {            if((line.empty() || nums[i] >= line.back()) && hash.find(nums[i]) == hash.end()) {                line.push_back(nums[i]);                dfs(nums, ret, line,i + 1);                line.pop_back();                hash.insert(nums[i]);       // the key point to avoid repeatation            }        }    }};

2、前缀生成法:

class Solution {public:    vector<vector<int>> findSubsequences(vector<int>& nums) {        set<vector<int>> seqs = {vector<int>(0)};       // increasing prefix        for (int i = 0; i < nums.size(); i++) {            vector<vector<int>> built(seqs.size());     // get a copy of seqs            std::copy(seqs.begin(), seqs.end(), built.begin());            for (auto seq : built) {                if (seq.empty() || nums[i] >= seq.back()) {                    seq.push_back(nums[i]);                    seqs.insert(seq);                }            }        }        vector<vector<int>> res;        for (auto seq : seqs)            if (seq.size() > 1) {                res.push_back(seq);            }        return res;    }};
原创粉丝点击