当前位置: 首页 > article >正文

递增子序列(回溯)

题目描述

给你一个整数数组 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

题解

如图所示,本题在使用回溯法时,需要解决以下两个问题:

(回溯法的使用详解见:组合(回溯+剪枝、图解)-CSDN博客)

  • 如何判断序列递增
  • 回溯遍历时如何进行去重

在使用回溯法时,我们用path数组保存遍历时路径上的每一个节点,用res保存最终结果,如下:

    vector<int> path;//保存当前结果
    vector<vector<int>> res;//保存最终结果

去除非递增序列

使用回溯法遍历nums时,由于我们用path数组保存当前遍历结果,因此对于下一个遍历到的元素num[i],我们只需要判断其与path数组中最后一个元素的大小。也就是说,

如果nums[i]>=path.back(),就说明如果将当前元素nums[i]加入到path数组中,序列就可以继续保持递增,那么就可以将nums[i]添加到path数组中;

否则,说明将当前元素nums[i]加入到path数组中后序列无法保持递增,就不能将nums[i]添加到path数组中

去重

由上图我们可以看到,去重是指对同一层上出现过的元素进行去重,由于按照题意我们无法对数组进行排序,因此不能使用之前使用过的去重逻辑(组合总和II(回溯、去重)-CSDN博客),需要重新设计去重方法。

假如我们现在不考虑回溯法,那么又该如何对一个有重复元素的数组nums进行去重呢?

如图所示,我们用一个set集合保存已经遍历过的元素,在每次遍历新元素的时候都在set中查找当前正在遍历的元素是否在set中出现过,如果当前正在遍历的元素在set中找到了,说明该元素已经出现过,也就是与之前的元素出现了重复。

为什么用set保存已经遍历过的元素呢?因为set数据结构天然不能保存重复的元素。

 

可以用其他数据结构保存已经遍历过的元素么?

当然可以,本题要求的-100 <= nums[i] <= 100,因此我们完全可以开一个大小为201的数组用于对已经遍历过的元素打上标记,用于标志该元素已经被遍历过

故而将上述想法假如到对上图中回溯法的单层去重逻辑中,即可完成本题的去重。整体代码如下

代码

解1

class Solution {
private:
    vector<int> path;
    vector<vector<int>> res;
public:
    void backing(vector<int>& nums,int startIndex)
    {
        if(path.size()>1)
            res.push_back(path);
        
        unordered_set<int> uset;//记录本层元素是否重复
        for(int i=startIndex;i<nums.size();i++)
        {
            /*
            判断当前元素
                1.如果nums[i]<path.back(),说明若加入元素就会使得序列非递增
                2.如果uset.find(nums[i])!=uset.end(),说明当前元素之前在同一层已经出现过
            */
            if((!path.empty() && nums[i]<path.back())
             || uset.find(nums[i])!=uset.end())
                continue;
            
            uset.insert(nums[i]);//记录当前已经使用过的元素
            path.push_back(nums[i]);//遍历路径上的节点
            backing(nums,i+1);
            path.pop_back();//回溯
        }
    }
    vector<vector<int>> findSubsequences(vector<int>& nums) {
        backing(nums,0);
        return res;
    }
};

解2

class Solution {
private:
    vector<int> path;//保存当前结果
    vector<vector<int>> res;//保存最终结果
public:
    void backing(vector<int>& nums,int startIndex)
    {
        if(path.size()>1)
            res.push_back(path);
        
        // unordered_set<int> uset;//记录本层元素是否重复
        int used[201]={0};
        for(int i=startIndex;i<nums.size();i++)
        {
            if((!path.empty() && nums[i]<path.back())
             || used[nums[i]+100])
                continue;
            
            // uset.insert(nums[i]);//记录当前已经使用过的元素
            used[nums[i]+100]=1;
            path.push_back(nums[i]);//遍历路径上的节点
            backing(nums,i+1);
            path.pop_back();//回溯
        }
    }
    vector<vector<int>> findSubsequences(vector<int>& nums) {
        backing(nums,0);
        return res;
    }
};


http://www.kler.cn/a/159711.html

相关文章:

  • 计算机网络 (1)互联网的组成
  • 写给初学者的React Native 全栈开发实战班
  • 前端vue 列表中回显并下拉选择修改标签
  • 时序论文20|ICLR20 可解释时间序列预测N-BEATS
  • OpenGL ES 共享上下文实现多线程渲染
  • css:盒子模型
  • 【EI征稿中#先投稿,先送审#】第三届网络安全、人工智能与数字经济国际学术会议(CSAIDE 2024)
  • 腾讯云轻量对象存储LighthouseCOS详细介绍
  • 如何快速了解在线客服行业的系统?
  • halcon如何设置窗口背景颜色?
  • 7.6 Windows驱动开发:内核监控FileObject文件回调
  • Linux服务器配置指南:网络、用户管理、共享服务及DNS配置详解
  • 虚拟线程原理及性能分析
  • EPICS Base 和许多未捆绑的 EPICS 扩展和支持模块
  • MongoInvalidArgumentError: Argument “docs“ must be an array of documents
  • MySQL 5.7安装-windows11
  • 单实例应用程序
  • 论文阅读:Distributed Initialization for VIRO with Position-Unknown UWB Network
  • Java利用TCP实现简单的双人聊天
  • openssl+EVP详解
  • 数据库增删改查(CRUD)进阶版
  • 安防视频监控/视频融合/云存储EasyCVR页面数据显示不全该如何解决?
  • 【Hive】——数据仓库
  • Linux服务器超级实用的脚本
  • 海思SD3403/SS928V100开发(11)双网卡同网段外部回环搭建测试
  • 车联网架构设计(二)_消息缓存