代码随想录刷题笔记 DAY 29 | 非递减子序列 No.491 | 全排列 No.46 | 全排列 II No. 47

文章目录

    • Day 29
      • 01. 非递减子序列(No. 491)
        • 1.1 题目
        • 1.2 笔记
        • 1.3 代码
      • 02. 全排列(No. 46)
        • 2.1 题目
        • 2.2 笔记
        • 2.3 代码
      • 03. 全排列 II(No. 47)
        • 3.1 题目
        • 3.2 笔记
        • 3.3 代码

Day 29

01. 非递减子序列(No. 491)

题目链接

代码随想录题解

1.1 题目

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

看完题目,很容易就可以发现,递增子序列就是 符合递增条件的子集,而且其中会包含重复元素,这就和昨天做到的题目 子集 II 十分相似,建议做完这道题再来看本题的题解

代码随想录刷题笔记 DAY 28 | 复原 IP 地址 No.93 | 子集 No.78 | 子集 II No.90

但是有一个很大的坑:

递增子序列是无法通过排序来去重的

回顾一下子集中如果出现重复的元素的去重方式

[1 2 2] ,将这个数组进行排序如果一层中遇到相同的元素就进行 continue

但递增子序列的问题就是它的顺序是固定的,不能通过排序来去重。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

比如说如上的这种情况,所有的节点都会去遍历相同的子树,这就导致了重复。

所以要做的是 层内去重,但是又不能通过排序的方式,所以我们可以想到在每一层去声明一个 record 当发现后续遍历的内容已经在 record 中出现的时候就跳过本次遍历。

这个 record 可以采用哈希方式实现,也可以使用列表方式去实现,显然哈希的实现方式更好

    public void backtracking(int index, int[] nums) {if (index > nums.length - 1) {return;}int[] record = new int[300];for (int i = index; i < nums.length; i++) {// 去重操作if (i > index && record[nums[i]+100] > 0) {continue;} else {record[nums[i] + 100] = 1;}// ...}}

因为 nums[i] 的范围是在 -100100 的范围内的,所以这里将 nums[i] + 100 存入数组,避免出现越界的情况。

这样就完成了层内的去重,剩下的就是考虑如何保证递增了。

显然这里也有两种选择:

  • 写一个方法,每次去判断 path 是否符合
  • 在递归过程中去判断

先来看比较容易理解的第一个方法

 public boolean isValid(List<Integer> path) {if (path.size() <= 1) {return false;}int currentMax = Integer.MIN_VALUE;for (int i : path) {if(i < currentMax) {return false;} else {currentMax = i;}}return true;
}

判断一个列表是否非递减,只需要在递增中不断更新 currentMax 并且确定后面的元素是否大于等于这个 current 即可。

在递归中也是相同的思路,只需要判断 nums[i] 是否大于等于 path.get(size() - 1) 也就是最后一个元素即可,否则,同样 continue

    if (!path.isEmpty() && nums[i] < path.get(path.size() - 1)) {continue;} else {record[nums[i] + 100] = 1;}

将这段代码和上面去重的代码组成一个 if 语句,写出代码。

1.3 代码
class Solution {List<Integer> path = new ArrayList<>();List<List<Integer>> res = new ArrayList<>();public List<List<Integer>> findSubsequences(int[] nums) {backtracking(0, nums);return res;}public void backtracking(int index, int[] nums) {if (index > nums.length - 1) {return;}int[] record = new int[300];for (int i = index; i < nums.length; i++) {// 去重操作if (i > index && record[nums[i]+100] > 0 ||!path.isEmpty() && nums[i] < path.get(path.size() - 1)) {continue;} else {record[nums[i] + 100] = 1;}path.add(nums[i]);if (path.size() > 1) {res.add(new ArrayList(path));}backtracking(i+1, nums);path.remove(path.size() - 1);}}
}

02. 全排列(No. 46)

题目链接

代码随想录题解

2.1 题目

给定一个不含重复数字的数组 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]]

提示:

  • 1 <= nums.length <= 6
  • -10 <= nums[i] <= 10
  • nums 中的所有整数 互不相同
2.2 笔记

上面说到过,回溯法可以解决排列问题,这就是一个经典的例子。

当遇到一开始思路不明确的回溯的题,建议大家先把树形结构画出来,这样各种操作就一目了然了。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

遍历到 1 之后就只能遍历 23 了,也就是每次遍历到一个节点,在这个节点剩余的遍历过程中,这个节点的值都不能出现,即在数组中删除掉这个遍历过的数。

但在数组中删除的操作时间复杂度相当高,所以很明显需要用到标记数组的方法。

与上题区分开,这里使用 boolean 数组

因为这里的去重是在路径中的,对全局的去重,所以标记数组的声明需要在层外

    boolean[] used;public List<List<Integer>> permute(int[] nums) {used = new boolean[30];// ...}public void backtracking(int[] nums) {// ...}

当路径中遇到遍历过的内容的时候就跳过

		for (int i = 0; i < nums.length; i++) {if (used[nums[i] + 10]) {continue;}// ...}

如果大家做过一些回溯的题目,很容易发现当层内去重的时候就不需要回溯,而路径去重就需要回溯,因为层内去重是在一层 for 循环中做的。

递归的终点,很显然就是当收集的数量等于数组长度的时候。

        if (path.size() == nums.length) {res.add(new ArrayList(path));return;}

写出代码

2.3 代码
class Solution {List<Integer> path = new ArrayList<>();List<List<Integer>> res = new ArrayList<>();boolean[] used;public List<List<Integer>> permute(int[] nums) {used = new boolean[30];backtracking(nums);return res;}public void backtracking(int[] nums) {if (path.size() == nums.length) {res.add(new ArrayList(path));return;}for (int i = 0; i < nums.length; i++) {if (used[nums[i] + 10]) {continue;}path.add(nums[i]);used[nums[i] + 10] = true;backtracking(nums);path.remove(path.size() - 1);used[nums[i] + 10] = false;}}
}

03. 全排列 II(No. 47)

题目链接

代码随想录题解

3.1 题目

给定一个可包含重复数字的序列 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]]

提示:

  • 1 <= nums.length <= 8
  • -10 <= nums[i] <= 10
3.2 笔记

做过上一题的朋友不用猜也能知道这个题要考察的是什么

就是在数组中加上重复的元素,考察层内去重的问题

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

所以这道题除了上题的路径去重还需要添加上层内去重。

但路径去重的时候应该注意,不能再以 nums[i] 作为标识了,因为内部含有相同的元素,所以应该使用 i 下标作为去重的标识。

		for (int i = 0; i < nums.length; i++) {if (used[i]) {continue;}// ...}

然后只需要加上层内去重的代码就大功告成了

本题几乎没有新的内容,只需要注意路径去重的逻辑即可。

3.3 代码
class Solution {List<Integer> path = new ArrayList<>();List<List<Integer>> res = new ArrayList<>();boolean[] used;public List<List<Integer>> permute(int[] nums) {used = new boolean[30];backtracking(nums);return res;}public void backtracking(int[] nums) {if (path.size() == nums.length) {res.add(new ArrayList(path));return;}for (int i = 0; i < nums.length; i++) {if (used[nums[i] + 10]) {continue;}path.add(nums[i]);used[nums[i] + 10] = true;backtracking(nums);path.remove(path.size() - 1);used[nums[i] + 10] = false;}}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/475535.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

普通人做抖音小店真的能赚钱吗?别在做美梦了,都醒醒吧!

大家好&#xff0c;我是电商糖果 糖果做电商七年了&#xff0c;这中间也起起落落过&#xff0c;2020年开始做抖音小店。 虽然靠着小店自己有了团队&#xff0c;翻了身。 但是只要有人问糖果&#xff0c;普通人做抖音小店真的能赚到钱吗&#xff1f; 我的回答依旧是看个人。…

2024年【安全员-C证】报名考试及安全员-C证考试资料

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 安全员-C证报名考试参考答案及安全员-C证考试试题解析是安全生产模拟考试一点通题库老师及安全员-C证操作证已考过的学员汇总&#xff0c;相对有效帮助安全员-C证考试资料学员顺利通过考试。 1、【多选题】《工伤保险…

Open CASCADE学习|TopoDS_Vertex与gp_Pnt相互转化

目录 gp_Pnt TopoDS_Vertex 关系和转换 使用场景 在Open CASCADE Technology (OCCT)中&#xff0c;TopoDS_Vertex和gp_Pnt是两种不同的数据类型&#xff0c;用于表示三维空间中的点。它们有不同的用途和特性&#xff1a; gp_Pnt gp_Pnt是OCCT几何库&#xff08;Geom&…

阿里云香港轻量应用服务器怎么样,建站速度快吗?

阿里云香港服务器中国香港数据中心网络线路类型BGP多线精品&#xff0c;中国电信CN2高速网络高质量、大规格BGP带宽&#xff0c;运营商精品公网直连中国内地&#xff0c;时延更低&#xff0c;优化海外回中国内地流量的公网线路&#xff0c;可以提高国际业务访问质量。阿里云服务…

FLUENT Meshing Watertight Geometry工作流入门 - 9 生成体网格

本视频中学到的内容&#xff1a; 讨论体网格的重要性&#xff0c;并了解生成体网格的不同方法 了解体网格质量&#xff0c;以及如何改进 视频链接&#xff1a; FLUENT Meshing入门教程-9生成体网格_哔哩哔哩_bilibili 体网格生成是使用大量离散体积或单元来离散化/表示计算模…

基于结点电压法的配电网状态估计算法matlab仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.本算法原理 4.1 结点电压法的基本原理 4.2 结点电压法在配电网状态估计中的应用 5.完整程序 1.程序功能描述 基于结点电压法的配电网状态估计算法.对配电网实施有效控制和操作的前提是实时数据库中数据…

力扣hot2--哈希

推荐博客&#xff1a; for(auto i : v)遍历容器元素_for auto 遍历-CSDN博客 字母异位词都有一个特点&#xff1a;也就是对这个词排序之后结果会相同。所以将排序之后的string作为key&#xff0c;将排序之后能变成key的单词组vector<string>作为value。 class Solution …

不知道不怪你:优秀网页UI的八大标准

hello&#xff0c;我是大千UI工场&#xff0c;本期分享如何设计漂亮的网页UI&#xff0c;先从优秀网页UI的标准讲起&#xff0c; 欢迎评论、转发&#xff0c;有需求可以私信接单。 优秀网页UI设计的八大标准如下&#xff1a; 一致性 网页UI设计应保持一致性&#xff0c;包括颜…

OpenAI超级视频模型Sora技术报告解读,虚拟世界涌现了

昨天白天&#xff0c;「现实不存在了」开始全网刷屏。 「我们这么快就步入下一个时代了&#xff1f;Sora简直太炸裂了」。 「这就是电影制作的未来」&#xff01; 谷歌的Gemini Pro 1.5还没出几个小时的风头&#xff0c;天一亮&#xff0c;全世界的聚光灯就集中在了OpenAI的So…

在职阿里6年,一个28岁女软件测试工程师的心声

简单的先说一下&#xff0c;坐标杭州&#xff0c;16届本科毕业&#xff0c;算上年前在阿里巴巴的面试&#xff0c;一共有面试了有6家公司&#xff08;因为不想请假&#xff0c;因此只是每个晚上去其他公司面试&#xff0c;所以面试的公司比较少&#xff09; 其中成功的有4家&am…

单调栈题目总结

单调栈 496. 下一个更大元素 I 503. 下一个更大元素 II 739. 每日温度 6227. 下一个更大元素 IV 模版归纳 「单调栈」顾名思义就是具有单调性的栈结构&#xff0c;一般常用于找到下一个更大的元素&#xff0c;即当前元素右侧第一个更大的元素 看下面一个例子&#xff1a…

【RT-DETR有效改进】利用EMAttention加深网络深度提高模型特征提取能力(特征选择模块)

一、本文介绍 本文给大家带来的改进机制是EMAttention注意力机制,它的核心思想是,重塑部分通道到批次维度,并将通道维度分组为多个子特征,以保留每个通道的信息并减少计算开销。EMA模块通过编码全局信息来重新校准每个并行分支中的通道权重,并通过跨维度交互来捕获像素级…