代码随想录刷题笔记 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.mzph.cn/news/688703.shtml

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

相关文章

UEditorPlus v3.8.0 文档导入支持直接粘贴 Markdown 格式,已知问题修复

UEditor 是由百度开发的所见即所得的开源富文本编辑器&#xff0c;基于MIT开源协议&#xff0c;该富文本编辑器帮助不少网站开发者解决富文本编辑器的难点。 UEditorPlus 是有 ModStart 团队基于 UEditor 二次开发的富文本编辑器&#xff0c;主要做了样式的定制&#xff0c;更…

大模型LLM训练显存消耗详解

参考论文&#xff1a;ZeRO: Memory Optimizations Toward Training Trillion Parameter Models 大模型的显存消耗一直都是面试常见的问题&#xff0c;这次我就彻彻底底的根据论文ZeRO中的调研和分析做一次分析 显存消耗的两个部分&#xff1a;Model States&#xff08;跟模型的…

离线数仓(三)【业务日志采集平台搭建】

前言 上一篇我们搭建完了用户行为日志数据的采集平台&#xff0c;其实也就是用两个 flume 采集数据到Kafka 中&#xff08;这种结构只有 source 和 channel 没有 sink&#xff09; 。离线数仓中的数据除了用户日志&#xff0c;还有就是业务数据了。 1、电商业务简介 1.1 电商…

Mac软件打开提示:已损坏,无法打开。您应该将它移到废纸娄 怎么解决?

新入手的苹果电脑打开软件出现&#xff1a;“已损坏&#xff0c;无法打开。您应该将它移到废纸娄” 或 “已损坏&#xff0c;打不开。推出磁盘映像”。这个怎么解决&#xff1f; 第一部分&#xff1a;&#xff08;注意&#xff1a;任何来源打开过了的&#xff0c;就直接去看下…

第三百五十三回

文章目录 1. 概念介绍2. 使用方法2.1 获取所有时区2.2 转换时区时间 3. 示例代码4. 内容总结 我们在上一章回中介绍了"分享一些好的Flutter站点"相关的内容&#xff0c;本章回中将介绍timezone包.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1. 概念介绍 我们在…

宠物赛道都卷出了哪些花样?媒介盒子分享

如今的宠物市场&#xff0c;已经从让宠物吃饱喝足的基本生理需求&#xff0c;拓展到五花八门的精神需求&#xff0c;与“马斯洛需求定理”高度一致。商家们看到宠物经济的潜力&#xff0c;不再满足于给人类造节&#xff0c;给毛孩子造节也是重中之重&#xff0c;今天媒介盒子就…

AJAX——HTTP协议

1 HTTP协议-请求报文 HTTP协议&#xff1a;规定了浏览器发送及服务器返回内容的格式 请求报文&#xff1a;浏览器按照HTTP协议要求的格式&#xff0c;发送给服务器的内容 1.1 请求报文的格式 请求报文的组成部分有&#xff1a; 请求行&#xff1a;请求方法&#xff0c;URL…

巨量广告测素材方法分享,如何拿到起量参考数据

测素材&#xff0c;测的是什么&#xff1f; 测素材只有两个目的&#xff1a; 1&#xff1a;测出跑量素材—方向 2&#xff1a;测出跑量素材—数据 方向对投手来说不是核心&#xff0c;从系统和投放的角度把结果数据给做素材的人讲到位就OK 数据是重点&#xff0c;投手一定…

【COMP337 LEC 5-6】

LEC 5 Perceptron &#xff1a; Binary Classification Algorithm 8 感应器是 单个神经元的模型 突触连接的强度取决于接受外部刺激的反应 X input W weights a x1*w1x2*w2....... > / < threshold Bias MaxIter is a hyperparameter 超参数 which has to be chosen…

网络防御保护——防火墙综合实验

一.实验拓扑 二.实验要求 1.办公区设备可以通过电信和移动两条链路上网(多对多的nat&#xff0c;并且需要保留一个公网ip不能用来转换)。 2.分公司设备可以通过移动链路和电信链路访问到dmz区域的http服务器。 3.分公司内部客户端可以通过公网地址访问到内部服务器。 4.FW1和FW…

C 语言 ConsoleRogueLike 控制台肉鸽游戏 DEVC++ VS2022都可用

使用 C 语言和 windows 的键盘检测函数和延迟函数&#xff0c;开发的控制台 roguelike 游戏 点开 .exe 文件立即进入游戏 AWSD 移动 J 攻击 K 加成buff 没有结束条件&#xff0c;除非碰到敌人。 其他模块功能还没来得及开发 author : 民用级脑的研发记录 DEVC 项目工程代码副本…

【Gitea】配置 Push To Create

引 在 Git 代码管理工具使用过程中&#xff0c;经常需要将一个文件夹作为仓库上传到一个未创建的代码仓库。如果 Git 服务端使用的是 Gitea&#xff0c;通常会推送失败。 PS D:\tmp\git-test> git remote add origin http://192.1.1.1:3000/root/git-test.git PS D:\tmp\g…

OpenHarmony—UIAbility组件与UI的数据同步

基于HarmonyOS的应用模型&#xff0c;可以通过以下两种方式来实现UIAbility组件与UI之间的数据同步。 使用EventHub进行数据通信&#xff1a;基于发布订阅模式来实现&#xff0c;事件需要先订阅后发布&#xff0c;订阅者收到消息后进行处理。使用globalThis进行数据同步&#…

【数据结构与算法】递归、回溯、八皇后 一文打尽!

&#x1f389;&#x1f389;欢迎光临&#x1f389;&#x1f389; &#x1f3c5;我是苏泽&#xff0c;一位对技术充满热情的探索者和分享者。&#x1f680;&#x1f680; &#x1f31f;特别推荐给大家我的最新专栏《数据结构与算法&#xff1a;初学者入门指南》&#x1f4d8;&am…

Vue3+Vite+TS+Pinia+ElementPlus+Router+Axios创建项目

目录 初始项目组成1. 创建项目1.1 下载项目依赖1.2 项目自动启动1.3 src 别名设置vite.config.ts配置文件tsconfig.json配置若新创项目ts提示 1.4 运行测试 2. 清除默认样式2.1 样式清除代码下载2.2 src下创建公共样式文件夹style2.3 main.js中引入样式2.4 安装sass解析插件 2.…

SNAT 与 DNAT

1.SNAT 1.1 SNAT 定义 SNAT 又称源地址转换。源地址转换是内网地址向外访问时&#xff0c;发起访问的内网ip地址转换为指定的ip地址&#xff08;可指定具体的服务以及相应的端口或端口范围&#xff09;&#xff0c;这可以使内网中使用保留ip地址的主机访问外部网络&#xff…

Leetcode 145.二叉树的后序遍历

题目 给你一棵二叉树的根节点 root &#xff0c;返回其节点值的 后序遍历 。 示例 1&#xff1a; 输入&#xff1a;root [1,null,2,3] 输出&#xff1a;[3,2,1] 示例 2&#xff1a; 输入&#xff1a;root [] 输出&#xff1a;[]示例 3&#xff1a; 输入&#xff1a;root…

应用回归分析:岭回归

岭回归&#xff0c;也称为Tikhonov正则化&#xff0c;是一种专门用于处理多重共线性问题的回归分析技术。多重共线性是指模型中的自变量高度相关&#xff0c;这种高度的相关性会导致普通最小二乘法&#xff08;OLS&#xff09;估计的回归系数变得非常不稳定&#xff0c;甚至无法…

32、IO/对文件读写操作相关练习20240218

一、使用fgets统计给定文件的行数 代码&#xff1a; #include<stdlib.h> #include<string.h> #include<stdio.h>int main(int argc, const char *argv[]) {FILE *fpNULL;if((fpfopen("./1.txt","r"))NULL)//只读形式打开1.txt文件{per…

【C++】类与对象【定义、访问限定符、this指针】

&#x1f308;个人主页&#xff1a;秦jh__https://blog.csdn.net/qinjh_?spm1010.2135.3001.5343&#x1f525; 系列专栏&#xff1a;http://t.csdnimg.cn/eCa5z 目录 面向过程和面向对象初步认识 类的引入 类的定义 成员变量命名规则的建议&#xff1a; 类的访问限定符及…