(81)491. 递增子序列(leetcode).

题目链接:
https://leetcode-cn.com/problems/increasing-subsequences/
难度:中等
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]。
	给定数组中可能包含重复数字,相等的数字应该被视为递增的一种情况。

要死了 头疼 牙疼 喉咙不舒服 。。。。 日啊 不会做 也不想做了 直接看答案吧,,,
第一种方法挺好理解的
枚举 共有 2的n次方种情况 全部枚举一次 判断是否为递增子序列即可 当然还要判断是否重复(这个地方不太懂)
使用二进制记录可能的情况

	几个例子吧: 序列 { 1  2  3 }
	共有8中情况 : 
			   { 1   2   3  }    对应数字(十进制)
				 0   0   0               0
				 0   0   1               1
				 0   1   0               2
				 0   1   1               3
				 1   0   0               4
				 1   0   1               5
				 1   1   0               6
				 1   1   1               7
	0 代表没有该数字  1代表选中该数字 当然其中有不符合条件的 

对于求hash值 的公式:

p可以去大于等于max{ai​}+1的任意一个值

class Solution {
    
    
public:
    vector<int> temp;
    vector<vector<int>> ans;
    unordered_set<int> s;
    int n;
    
    // 找出 对应的数字
    void findSubsequences(int mask, vector<int>& nums) {
    
    
        temp.clear();
        for (int i = 0; i < n; ++i) {
    
    
            if (mask & 1) {
    
    
                temp.push_back(nums[i]);
            }
            mask >>= 1;
        }
    }
    // 判断 子序列(temp) 是不是递增子序列
    bool check() {
    
    
        for (int i = 1; i < temp.size(); ++i) {
    
    
            if (temp[i] < temp[i - 1]) {
    
    
                return false;
            }
        }
        return temp.size() >= 2;
    }
    // 得到hash值
    int getHash(int base, int mod) {
    
    
        int hashValue = 0;
        for (const auto &x: temp) {
    
    
            hashValue = 1LL * hashValue * base % mod + (x + 101);
            hashValue %= mod;
        }
        return hashValue;
    }

    vector<vector<int>> findSubsequences(vector<int>& nums) {
    
    
        n = nums.size();
        // 共有 2的n次方 种情况 即 1<<n
        // 数字 i 所对应的子序列
        for (int i = 0; i < (1 << n); ++i) {
    
    
            // 将找出的子序列放到 temp 中
            findSubsequences(i, nums);
            // 求出 hash 值
            int hashValue = getHash(263, int(1E9) + 7);
            // 递增 不存在
            if (check() && s.find(hashValue) == s.end()) {
    
    
                ans.push_back(temp);
                s.insert(hashValue);
            }
        }
        return ans;
    }

};

另一个就是 递归 还是递归方便
还是枚举 每个数字有两种情况 选或者不选 当其中一种情况枚举至序列最后时 结束 (需要一个参数记录当前位置)
在选择的时候 只有当当前数值大于上一个数值时才可以选中 这满足了序列的递增 还要解决序列的不重复
对于 … a … b … (cur此时指向b a是上一个选择的元素) 对于序列 a b 共有四种情况 a选b选 a选b不选 a不选b选 a不选b不选
若 a b值相同 可以看出 a选b不选 a不选b选 是等价的 只要排除一种即可 那么 只有上一个元素不等于当前元素的时候 当前元素不选择

class Solution {
    
    
public:
    vector<int> temp;
    vector<vector<int>> ans;

    void dfs(int cur,int last,vector<int>& nums){
    
    
        int n = nums.size();
        // 递归条件 枚举至端点跳出
        if(n==cur){
    
    
            if(temp.size()>=2){
    
    
                ans.push_back(temp); 
            }
            return;
        }
        // 若当前值大于前一个值
        //   相当于 
        //     temp.push_back(nums[cur]);
        //     dfs(cur+1,nums[cur],nums);
        //     temp.pop_back();
        //     dfs(cur+1,last,nums);
        // 若当前值等于前一个值
        //     temp.push_back(nums[cur]);
        //     dfs(cur+1,nums[cur],nums);
        //     temp.pop_back();
        //     {不选择当前元素} 此种情况排除
        if(nums[cur]>=last){
    
    
            temp.push_back(nums[cur]);
            dfs(cur+1,nums[cur],nums);
            temp.pop_back();
        }
        if(nums[cur]!=last){
    
    
            dfs(cur+1,last,nums);
        }
    }

    vector<vector<int>> findSubsequences(vector<int>& nums) {
    
    
        dfs(0, INT_MIN, nums);
        return ans;
    }

};

先这样 最近几天有点难受 睡觉,,,

猜你喜欢

转载自blog.csdn.net/li_qw_er/article/details/108216663