算法练习第26天|46.全排列、47全排列II

46.全排列

46. 全排列 - 力扣(LeetCode)icon-default.png?t=N7T8https://leetcode.cn/problems/permutations/description/

题目描述:

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

思路分析:

今天的全排列题目就不在和之前的求组合的问题一样了,之前从一个集合中取子集,需要使用startIndex来控制每次搜索开始的位置。但是全排列则不能用startIndex来控制搜索的开始位置,因为一旦用了startIndex,则startIndex前面的元素就遍历不到了。所以,全排列的思路就是每次遍历都是将nums数组从头到尾遍历一遍(注意是每一次遍历,就是常写的for循环那里),已经在path中的数字不能再用。

那么如何使得用过的数字不再用呢?我这里的做法是使用一个used数组来做记录。对应的树形结构如下:

 下面开始回溯三部曲:

第一步:确认回溯函数的参数和返回值。返回值老规矩void,参数除了题目的nums原数组,还需要used数组。通过used数组每次传进来上一层递归所使用元素的情况。used数组和nums数组长度一样。used某个位置的元素为0,则表明nums对应位置的元素没被用过;为1则表示被用过。

    vector<int> path;vector<vector<int>> result;void backTracking(vector<int> & nums, vector<int>& used){}

第二步,确定回溯中之条件。当path搜集到的元素个数和nums一样时,说明遍历完了,可以用result记录了。

void backTracking(vector<int> & nums, vector<int>& used){if(path.size() == nums.size()){result.push_back(path);return;}
}

第三部:单层搜索逻辑。这个时候就要用到前面所说的 每次遍历都是将nums数组从头到尾遍历一遍,

void backTracking(vector<int> & nums, vector<int>& used){if(path.size() == nums.size()){result.push_back(path);return;}//每次都是从头开始遍历nums中的元素for(int i = 0; i<nums.size(); i++){if(used[i] == 1){  //如果这个元素对应的标志位为1,表明已经用过,则continue进入下一轮循环,即开始检索下一个元素continue;}//走到这一步说明当前元素还没被用过,马上要用used[i] = 1;  //标志为置0path.push_back(nums[i]);  //path记录backTracking(nums, used);  //递归//两步回溯used[i] = 0;path.pop_back();}}

整体代码如下:

class Solution {
public:vector<int> path;vector<vector<int>> result;void backTracking(vector<int> & nums, vector<int>& used){if(path.size() == nums.size()){result.push_back(path);return;}for(int i = 0; i<nums.size(); i++){if(used[i] == 1){continue;}used[i] = 1;path.push_back(nums[i]);backTracking(nums, used);used[i] = 0;path.pop_back();}}vector<vector<int>> permute(vector<int>& nums) {int N = nums.size();vector<int> used(N,0);backTracking(nums, used);return result;}
};

 由于used数组不是局部变量,它需要在每次递归时都保留上一层元素是否使用的具体情况,所以我们将其初始化在permute函数中,并使用引用类型的形参来保持数据的更新。如果想节省空间,vector<int> used可以换成bool类型,即vector<bool> used。

总结

大家此时可以感受出排列问题的不同:

  • 每层都是从0开始搜索而不是startIndex
  • 需要used数组记录path里都放了哪些元素了

47.全排列 II

47. 全排列 II - 力扣(LeetCode)icon-default.png?t=N7T8https://leetcode.cn/problems/permutations-ii/description/

题目描述:

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

 思路分析:

本题与46题不同的是,46题所有元素都不重复,所以不用担心因为元素重复所带来的排列重复的问题,所以46题可以好不担心的每次都从0位置开始遍历nums数组。

但是本题存在了重复元素,需要当心得到重复的排列,所以可以先画出对应的树形结构,看看重复出现在什么地方:

 在40组合问题II、和90子集II中我们分别详细讲解了组合问题和子集问题如何去重。去重的前提是对nums原数组进行排序。我们尝试一下排序看行不行。发现当对数组进行排序后进行去重依然试用这道排列题。因为之前的i>0 && nums[i-1] == nums[i]可以帮助我们判断当前元素与其前一个元素是否相等。如果相等,那么去重问题的关键就成了怎么限定我访问的是第二个重复的元素呢?

首先,我们提前对数组进行了排序,所以能保证元素的增长顺序,其次,当i>0 && nums[i-1] == nums[i]这个条件满足时,说明有两个相邻元素时相等的,那么此时used数组就可以派上用场了。访问两个相同元素的前一个时,used置1,然后递归回溯,回溯后used对应位置会置0。走到这里表明两个相同元素中的前一个已经访问完毕,然后for循环i++,会访问到两个相同元素中的后一个,也就是 i>0 && nums[i-1] == nums[i]满足了,但是还不够,因为此时该元素不能被记录,所以还需要加的限制条件就是used[i-1] = 0, i>0 && nums[i-1] == nums[i]&&used[i-1] = 0 表明这是两个相同元素中的后一个且used[i-1] = 0表明前面的元素已经遍历过了,该记录的也记录了,所以着第二个元素就直接continue跳过。

整体代码如下:

class Solution {
public:vector<int> path;vector<vector<int>> result;void backtracking(vector<int> &nums, vector<bool>& used){if(path.size() == nums.size()){result.push_back(path);return;}//由于时排列问题,不用startIndex,每次都从头遍历numsfor(int i = 0; i< nums.size(); i++){//path已经记录过的,标志为1,直接continue到下一个元素if(used[i] == true){continue;}//如果当前元素没有用过,那么就该判断是不是相同元素中的后一个,如果是,直接continueif(i>0 && nums[i-1] == nums[i] && used[i-1]==false){continue; }//正常元素的记录、递归、回溯used[i] = true;path.push_back(nums[i]);backtracking(nums, used);used[i] = false;path.pop_back();}}vector<vector<int>> permuteUnique(vector<int>& nums) {sort(nums.begin(),nums.end());vector<bool> used(nums.size(), false);backtracking(nums,used);return result;}
};

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

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

相关文章

HTML、ASP.NET、XML、Javascript、DIV+CSS、JQuery、AJax的起源与简介

目录 HTML简介: 起源&#xff1a; ASP.NET简介&#xff1a; 起源: XML简介: 起源: JavaScript简介&#xff1a; 起源: DIVCSS简介: 起源&#xff1a; JQuery简介: 起源: AJax简介&#xff1a; HTML简介: HTML(Hyper Text Markup Language&#xff0c;超文本标记语言…

STM32 | 超声波实战

​01、上节回顾 STM32 | HC-SR04 超声波测距模块 | DHT11数字温湿度传感器(第七天)STM32 | 数字温湿度传感器DHT11STM32 | HC-SR04 超声波测距模块STM32 | DHT11数字温湿度传感器实战02、超声波图示 03、超声波头文件 #ifndef __SR04_H#define __SR04_H​#include "stm…

在鸿蒙中身份校验的手势密码的实现

在harmony中它提供了默认的组件PatternLock()&#xff1b; 这个就能直接显示九宫格密码验证 并且他有两个主要的回调事件 .onDotConnect密码输入选中宫格圆点时触发该回调 .onPatternComplete&#xff1a;密码输入结束时触发该回调 //如代码实现 PatternLock().sideLength(32…

OceanBase 内存研究(OceanBase 3.2.4.5)

内存结构 从官网的结构图可以看出&#xff0c;一台observer可使用的总内存(memory_limit)包括 系统内存(system_memory) 和 租户内存(sys租户与普通租户) 系统内存 系统内存system_memory 属于 observer 的内部内存&#xff0c;允许其它租户共享使用该内存资源 (root10.0.0.…

vmware 正版免费下载

Broadcom 已经收购了 vmware 并且对普通用户提供免费服务. 那么我们怎么去获取这个玩意呢, 注册完之后打开就是这么个狗屎 , 根本不知道在哪里下载&#xff0c;注册的时候还不能用国内邮箱更是超级狗屎 转到 dashboard 搜索 workstation Pro你会搜索到这么一个奇怪的网址然后…

SSM与Mamba模型学习

transformer的缺陷 自注意力机制的计算范围只限于窗口内&#xff0c;不能直接处理窗口外的元素&#xff0c;不能照顾到整个序列。 由于计算复杂度随着窗口的长度呈几何平方式增长&#xff0c;所以不能一味地增加窗口长度来解决。 Transformer本质上是通过位置编码将序列数据空…

计算机网络工程师需要掌握的知识点

网络基础 网络协议OSI参考模型TCP/IP 体系结构广域网与接入网技术&#xff1a;HDLC、PPP。xDSL、HFCIEEE802标准、以太网技术。网桥、交换机、无线局域网&#xff08;WLAN&#xff09;、VLAN、TRUNK、GVRP、STP、综合布线系统IP地址、子网划分、CIDR、ARP、ICMP、IPV6、TCP、UD…

AI在线UI代码生成,不需要敲一行代码,聊聊天,上传图片,就能生成前端页面的开发神器

ioDraw的在线UI代码生成器是一款开发神器&#xff0c;它可以让您在无需编写一行代码的情况下创建前端页面。 主要优势&#xff1a; 1、极简操作&#xff1a;只需聊天或上传图片&#xff0c;即可生成响应式的Tailwind CSS代码。 2、节省时间&#xff1a;自动生成代码可以节省大…

微信小程序-页面配置

一、页面配置文件的作用 小程序中&#xff0c;每个页面都有自己的.json配置文件&#xff0c;用来对当前页面的窗口外观、页面效果等进行配置 二、页面配置和全局配置的关系 小程序中&#xff0c;app.json中的window节点&#xff0c;可以全局配置小程序中每个页面的窗口表现 …

FastDFS分布式文件系统——上传本地文件

目录 安装FastDFS FastDFS 使用Java客户端上传本地文件到FastDFS服务器上 pom.xml fastdfs_conf配置文件 FastDFS 测试 安装FastDFS 1、用FastDFS一步步搭建文件管理系统 - bojiangzhou - 博客园 (cnblogs.com)2、FastDFS文件上传功能封装 - 动力节点 (bjpowernode.com)…

Kotlin native 打包DLL 与 C# 代码间的相互访问

指定文件打包&#xff1a;kotlinc-native 需要先安装 kotlin-native-prebuilt-windows-x86_64-2.0.0.zipkotlinc-native -p dynamic -o example Example.k kotlin代码&#xff1a; OptIn(ExperimentalNativeApi::class) CName("exampleFunction") fun example…

哈希表散列表

文章目录 哈希表概述哈希表详解什么是 Hash 冲突哈希冲突的常见解决方法HashMap 如何解决 Hash 冲突的 哈希表概述 哈希表&#xff08;Hash Table&#xff09;是一种数据结构&#xff0c;用于实现键值对的存储和快速检索。它通过将键映射到数组的索引位置来实现高效的查找操作…

ERC-7401:嵌套 NFT 标准的全新篇章

在数字资产和区块链技术迅速发展的今天&#xff0c;非同质化代币&#xff08;NFT&#xff09;已经成为了一种重要的资产形式&#xff0c;广泛应用于艺术、游戏、收藏品等多个领域。随着市场需求的多样化&#xff0c;传统的 NFT 标准如 ERC-721 和 ERC-1155 已经不能完全满足用户…

Keras深度学习框架实战(2):估计模型训练所需的样本量

1、模型训练样本量评估概述 1.1 样本量评估的意义 预估模型需要的样本量对于机器学习项目的成功至关重要&#xff0c;以下是几个主要原因&#xff1a; 防止过拟合与欠拟合&#xff1a; 过拟合&#xff1a;当模型在训练数据上表现极好&#xff0c;但在未见过的测试数据上表现糟…

5步3分钟0基础搭建,轻松搭建《雾锁王国》私人服务器

继《幻兽帕鲁》游戏爆火之后&#xff0c;与它同类型的《雾锁王国》也是强力刷屏&#xff0c;不分伯仲&#xff0c;在 Steam 上的评分一直稳定在“特别好评”&#xff0c;让小伙伴们很“上头”。就在两者游戏玩家反响爆火的同时&#xff0c;官方服务器人数爆满&#xff0c;卡顿频…

关闭数据库默认配置配置自定义数据库

在实际项目中使用了通过配置中心配了数据库&#xff0c;而我们改了application.yml并没有起作用&#xff0c;我们可以手动创建一个配置类来定义自定义的数据源&#xff0c;并在Spring容器中注册它 PrimaryBeanpublic DataSource customDataSource() {return DataSourceBuilder.…

C语言Linux进度条模拟

在Linux字符界面中&#xff0c;使用yum、apt下载东西时会有一个图形化的进度条&#xff0c;可以告诉我们任务的执行进度。 我们也可以通过C语言实现一个类似的进度条&#xff0c;并且可以做得更加美观。以后我们自己写的程序需要显示进度时就可以去调用我们自己实现的进度条。 …

【typescript/flatbuffer】在websocket中使用flatbuffer

目录 说在前面场景fbs服务器代码前端typescript代码问题 说在前面 操作系统&#xff1a;Windows11node版本&#xff1a;v18.19.0typescript flatbuffer版本&#xff1a;24.3.25 场景 服务器(本文为golanggin)与前端通信时使用flatbuffer进行序列化与反序列化通信协议为websock…

从0开始制作微信小程序

目录 前言 正文 需要事先准备的 需要事先掌握的 什么是uniapp 平台应用的分类方式 什么是TypeScript 创建项目 项目文件作用 源码地址 尾声 &#x1f52d; Hi,I’m Pleasure1234&#x1f331; I’m currently learning Vue.js,SpringBoot,Computer Security and so on.&#x1…