递增子序列(一个完美的题型,解释很多)

说明

  • 这个题型说明了很多问题,首先是startIndex的使用
  • 其次是同一数层的去重,和前面的去重还不一样,因为原数组是不能排序的
  • 还有什么时候应该在终止条件中return

题目

给你一个整数数组 nums ,找出并返回所有该数组中不同的递增子序列,递增子序列中 至少有两个元素 。你可以按 任意顺序 返回答案。

数组中可能含有重复元素,如出现两个整数相等,也可以视作递增序列的一种特殊情况。

示例 1:

输入:nums = [4,6,7,7]
输出:[[4,6],[4,6,7],[4,6,7,7],[4,7],[4,7,7],[6,7],[6,7,7],[7,7]]
示例 2:

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

提示:

1 <= nums.length <= 15
-100 <= nums[i] <= 100

思路

思路于代码中,注意!path.empty() && nums[i] < path.back()的顺序不能反

代码

// 输入:nums = [4,6,7,7]
// 输出:[[4,6],[4,6,7],[4,6,7,7],[4,7],[4,7,7],[6,7],[6,7,7],[7,7]]

//子数列,又称子序列,在数学中,某个序列的子序列是从最初序列通过去除某些元素但不破坏余下
//元素的相对位置(在前或在后)而形成的新序列,注意是不能通过破坏原有数组的相对顺序的,所以
//不能对原数组进行排序,这个是最重要的一点
//那么没有排序的原数组怎么去重呢,要对同一层的所有元素使用unordered_set进行去重
class Solution {
private:
    vector<int> path;
    vector<vector<int>> result;
    void backing(vector<int>& nums, int startIndex) {
        if(path.size() >= 2) {
            result.push_back(path);
            //return;//如果返回的话那么就是一个回溯的过程,无法往下取
        }

        unordered_set<int> usedSet;
        for (int i = startIndex; i < nums.size(); i++) {
            //判断什么时候应该看看这个元素是不是应该进入path
            //首先如果path内部没有元素,那么直接收录nums[i]
            //如果这个nums[i]比path最后一个元素还要小的话,那么path不用收录
            //如果这个元素已经使用过那么path也不用收录

            //综上所述,那么什么情况下需要跳过呢
            //(1):path不是空的而且path的最后一个元素要比nums[i]大
            //(2):这个元素已经在同一层当中使用过了

            //注意!path.empty() && nums[i] < path.back()的顺序不能反

            if((!path.empty() && nums[i] < path.back()) || usedSet.find(nums[i]) != usedSet.end()){
                continue;
            }
            usedSet.insert(nums[i]);
            path.push_back(nums[i]);
            backing(nums, i + 1);
            path.pop_back();
        }
    }
public:
    vector<vector<int>> findSubsequences(vector<int>& nums) {
        backing(nums, 0);
        return result;
    }
};
posted @ 2023-04-11 13:00  铜锣湾陈昊男  阅读(18)  评论(0)    收藏  举报