Leecode 491. 非递减子序列

题目描述

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

解题思路与代码

本题和之前的有重复元素的子集那道题的回溯有点相似,都是其中会有一些重复的元素,而有重复的元素就要涉及到去重的操作。在那道子集的题目中,去重是通过先对集合中元素进行排序,随后再在回溯中使用start变量的条件判断来进行去重。但本题不同的点在于,要求输出的是原序列中非递减的一部分子序列,这意味着我们需要保持原本的排序关系,不能再先对原本序列进行排序操作。从而也就无法用之前那样的方式来进行去重了。本题去重考虑使用unordered_set容器来记录每一层中的变量是否已经在回溯递归中使用过。可以写出如下代码:

class Solution {
public:
vector<vector<int>> result;
vector<int> curVec; void backTracking(const vector<int>& nums, int start){
if(curVec.size() >= 2){ // 只要长度大于等于2的子序列都进行存储
result.push_back(curVec);
}
unordered_set<int> used; // 用于记录已经用过的元素
for(int i = start; i < nums.size(); i++){
if(!curVec.empty() && nums[i] < curVec.back()) continue; // 如果当前元素比子序列中最后一个元素小,则跳过
if(used.find(nums[i]) != used.end()) continue; // 如果子序列中已经用过当前元素,则跳过
curVec.push_back(nums[i]);
used.insert(nums[i]);
backTracking(nums, i + 1);
curVec.pop_back();
}
} vector<vector<int>> findSubsequences(vector<int>& nums) {
backTracking(nums, 0);
return result;
}
};

Leecode 46. 全排列

题目描述

给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。

  • 示例 1:

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

输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]

  • 示例 2:

输入:nums = [0,1]

输出:[[0,1],[1,0]]

  • 示例 3:

输入:nums = [1]

输出:[[1]]

解题思路与代码展示

本题要求的是数组中数字的全排列,排列与之前做过的组合的区别在于排列需要关注每个元素出现的顺序,而组合中只需要关注出现了哪些元素。既然是全排列,那么使用回溯法过程中,进行存放结果的条件判断应该非常简单,只需要当前数组中的元素个数等于原数组中的个数即可。但关键在于我们需要如何判断回溯过程中,每一个元素是否已经出现在过当前数组里。因此我们考虑使用一个存放布尔类型的vector来存放某个元素是否被使用过。由此我们可以写出下面代码:

class Solution {
public:
vector<vector<int>> result;
vector<int> curVec; void backTracking(vector<int>& nums, vector<bool> used){
if(curVec.size() == nums.size()){ // 当前数组中的元素数量和原数组元素数量相等,则存放结果
result.push_back(curVec);
return;
}
for(int i = 0; i < nums.size(); i++){
if(used[i]) continue; // 如果当前数已经用过,则直接跳过
curVec.push_back(nums[i]); // 没用过,则将其放到当前数组中
used[i] = true; // 更新used向量
backTracking(nums, used); // 递归
used[i] = false; // 回溯
curVec.pop_back(); // 回溯
}
} vector<vector<int>> permute(vector<int>& nums) {
result.clear();
curVec.clear();
vector<bool> used(nums.size(), false); // 使用used向量来存放每个元素是否有被使用过
backTracking(nums, used);
return result;
}
};

47. 全排列 II

题目描述

给定一个可包含重复数字的序列 nums ,按任意顺序 返回所有不重复的全排列。

  • 示例 1:

输入:nums = [1,1,2]

输出:

[[1,1,2],
[1,2,1],
[2,1,1]]
  • 示例 2:

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

输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]

解题思路与代码展示

本题与上一题比较相似,区别在于原始数组中可能出现重复元素。如果使用上面的代码会产生重复。为了去重可以考虑使用set来存放结果,并在最后将set转换为vector即可。

class Solution {
public:
set<vector<int>> result; // 使用set来存放结果
vector<int> curVec; void backTrack(vector<int>& nums, vector<bool> used){
if(curVec.size() == nums.size()){
result.insert(curVec);
return;
}
for(int i = 0; i < nums.size(); i++){
if(used[i]) continue;
used[i] = true;
curVec.push_back(nums[i]);
backTrack(nums, used);
curVec.pop_back();
used[i] = false;
}
} vector<vector<int>> permuteUnique(vector<int>& nums) {
result.clear();
curVec.clear();
vector<bool> used(nums.size(), false);
backTrack(nums, used);
vector<vector<int>> re(result.begin(), result.end()); // 将set转换为vector
return re;
}
};

上面代码中的逻辑和上题几乎完全一致,区别仅在于使用了set容器来进行去重。

代码随想录第二十五天 | Leecode 491. 非递减子序列、46. 全排列、47. 全排列 II的更多相关文章

  1. NeHe OpenGL教程 第二十五课:变形

    转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...

  2. Gradle 1.12用户指南翻译——第二十五章. Scala 插件

    其他章节的翻译请参见: http://blog.csdn.net/column/details/gradle-translation.html 翻译项目请关注Github上的地址: https://g ...

  3. centos lamp/lnmp阶段复习 以后搬迁discuz论坛不需要重新安装,只需修改配置文件即可 安装wordpress 安装phpmyadmin 定时备份mysql两种方法 第二十五节课

    centos  lamp/lnmp阶段复习 以后搬迁discuz论坛不需要重新安装,只需修改配置文件即可 安装wordpress  安装phpmyadmin  定时备份mysql两种方法  第二十五节 ...

  4. javaSE第二十五天

    第二十五天    399 1:如何让Netbeans的东西Eclipse能访问.    399 2:GUI(了解)    399 (1)用户图形界面    399 (2)两个包:    399 (3) ...

  5. SQL注入之Sqli-labs系列第二十五关(过滤 OR & AND)和第二十五A关(过滤逻辑运算符注释符)

    开始挑战第二十五关(Trick with OR & AND) 第二十五关A(Trick with comments) 0x1先查看源码 (1)这里的or和and采用了i正则匹配,大小写都无法绕 ...

  6. “全栈2019”Java多线程第二十五章:生产者与消费者线程详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...

  7. “全栈2019”Java第二十五章:流程控制语句中循环语句while

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...

  8. 孤荷凌寒自学python第二十五天初识python的time模块

    孤荷凌寒自学python第二十五天python的time模块 (完整学习过程屏幕记录视频地址在文末,手写笔记在文末) 通过对time模块添加引用,就可以使用python的time模块来进行相关的时间操 ...

  9. x264代码剖析(十五):核心算法之宏块编码中的变换编码

    x264代码剖析(十五):核心算法之宏块编码中的变换编码 为了进一步节省图像的传输码率.须要对图像进行压缩,通常採用变换编码及量化来消除图像中的相关性以降低图像编码的动态范围.本文主要介绍变换编码的相 ...

  10. 风炫安全WEB安全学习第二十五节课 利用XSS键盘记录

    风炫安全WEB安全学习第二十五节课 利用XSS键盘记录 XSS键盘记录 同源策略是浏览器的一个安全功能,不同源的客户端脚本在没有明确授权的情况下,不能读写对方资源.所以xyz.com下的js脚本采用a ...

随机推荐

  1. Luogu P3959 宝藏 题解 [ 紫 ] [ 状压 dp ] [ 二项式定理 ]

    宝藏:一个对着蓝书代码调都能调两个小时的大毒瘤,但是思路还是很值得借鉴的,有普通状压和三进制状压两种做法,或者暴搜剪枝也可以(这里不介绍暴搜剪枝做法). 普通状压做法 观察到 \(n\le 12\), ...

  2. Markdown语法基础教学

    Markdown语法基础教学 简介 Markdown是一种轻量级的标记语言,它允许人们使用易读易写的纯文本格式编写文档,然后转换成结构化的HTML.它的目标是实现"易读易写",并且 ...

  3. 重磅发布!DeepSeek 微调秘籍揭秘,一键解锁升级版全家桶,AI 玩家必备神器!

    DeepSeek V3/R1 火爆全网,基于原始模型的解决方案和 API 服务已随处可见,陷入低价和免费内卷. 如何站在巨人肩膀上,通过后训练(post-training)结合专业领域数据,低成本打造 ...

  4. [BZOJ4671] 异或图 题解

    我能说什么!抽象了这! 看到 \(n\le 10\) 的黑题顿感大事不妙. 我们考虑设 \(f(i)\) 表示将 \(n\) 个点划分为至少 \(i\) 个连通块时的方案数.我们可以暴力枚举每个点在哪 ...

  5. 分块-byx

    Update:2025.5.25 树状数组是基于二进制划分与倍增的思想,线段树基于分治的思想.之所以能够高效修改和查询,就是把序列分成了大大小小的"段",花费额外(增加空间,空间换 ...

  6. 【markdown】各种markdown的骚操作

    目录 1.给图片居中.加题注 2. 文字添加下划线 3. 文字高亮.自定义高亮的颜色 4. 博客文章生成目录 5. markdown 实现页内跳转 6. 数学公式调大尺寸.右编号 7. 折叠内容 8. ...

  7. python 二级 标准库

    1.turtle 函数 包括窗体函数.画笔状态.画笔运动函数 random库 3.time 时间处理.时间格式化.时间计时

  8. selenium 提示消息一闪而过,怎么定位

    F12 点击source 下的暂停按钮

  9. windows在Apple Developer创建打包证书的简单教程

    在uniapp上做ios开发,其开发证书必须在Apple Developer(苹果开发者中心)上使用自己个人或自己公司的开发者账号,创建打包的证书,然后上架的时候使用同一个账号上架Apple Deve ...

  10. Vue3-DeepSeek-Chat流式AI对话|vite6+vant4+deepseek智能ai聊天助手

    原创新作vue3.5+deepseek+vant4+vant4仿DeepSeek-R1流式输出ai聊天对话. deepseek-vue3-chat : 实战2025智能大模型ai会话,基于Vue3+V ...