leetcode-master/problems/0491.递增子序列.md

3.6 KiB
Raw Blame History

题目地址

思路

这道题可以说是深度优先搜索,也可以说是回溯法,其实我更倾向于说它用回溯法,因为本题和90. 子集 II非常像,差别就是90. 子集 II可以通过排序,在加一个标记数组来达到去重的目的。

去重复的逻辑,关键在于子序列的末尾,如果子序列的末尾重复出现一个元素,那么该序列就是重复的了,如图所示:

在递归的过程中 if ((subseq.empty() || nums[i] >= subseq.back()) && uset.find(nums[i]) == uset.end()) 这个判断条件一定要想清楚, 如果子序列为空或者nums[i]>=子序列尾部数值,同时 这个nums[i] 不能出现过, 因为一旦出现过就 是一个重复的递增子序列了。

C++代码

class Solution {
private:
void backtracking(vector<int>& nums, vector<vector<int>>& result, vector<int>& subseq, int startIndex) {
    if (subseq.size() > 1) {
        result.push_back(subseq);
        // 注意这里不要加return因为要取所有的可能
    }
    unordered_set<int> uset; // 使用set来对尾部元素进行去重
    for (int i = startIndex; i < nums.size(); i++) {
        if ((subseq.empty() || nums[i] >= subseq.back())
                && uset.find(nums[i]) == uset.end()) {
            subseq.push_back(nums[i]);
            backtracking(nums, result, subseq, i + 1);
            subseq.pop_back();
            uset.insert(nums[i]);//在回溯的时候,记录这个元素用过了,后面不能再用了
        }
    }
}
public:
    vector<vector<int>> findSubsequences(vector<int>& nums) {
        vector<vector<int>> result;
        vector<int> subseq;
        backtracking(nums, result, subseq, 0);
        return result;
    }
};

一位师弟在评论中对代码进行了改进,效率确实高了很多,优化后如图:

改动的地方主要是将去重的逻辑中把 unordered_set 改成了 数组。

用数组替换unordered_set 确实可以快很多unordered_set底层符号表也是哈希表理论上不应该差多少。

估计程序运行的时候对unordered_set 频繁的insertunordered_set需要做哈希映射也就是把key通过hash function映射为唯一的哈希值费了些时间。

用数组来做哈希,效率就高了很多,再加上题目中也说了,数值范围[-100,100],所以用数组正合适。

这个事实告诉我们,使用哈希法的时候,条件允许的话,能用数组尽量用数组。

优化后的代码如下:

class Solution {
private:
void backtracking(vector<int>& nums, vector<vector<int>>& result, vector<int>& subseq, int startIndex) {
    if (subseq.size() > 1) {
        result.push_back(subseq);
        // 注意这里不要加return因为要取所有的可能
    }
    int hash[201] = {0}; // 这里使用数组来进行去重操作,题目说数值范围[-100, 100]
    for (int i = startIndex; i < nums.size(); i++) {
        if ((subseq.empty() || nums[i] >= subseq.back())
                && hash[nums[i] + 100] == 0) {
            subseq.push_back(nums[i]);
            backtracking(nums, result, subseq, i + 1);
            subseq.pop_back();
            hash[nums[i]+100] = 1;
        }
    }
}
public:
    vector<vector<int>> findSubsequences(vector<int>& nums) {
        vector<vector<int>> result;
        vector<int> subseq;
        backtracking(nums, result, subseq, 0);
        return result;
    }
};