DAY32:回溯算法(七)全排列+全排列Ⅱ(排列问题)

news2024/10/7 18:32:06

文章目录

    • 46.全排列
      • 思路
        • 树形图
        • used数组的作用
      • 伪代码
      • 完整版
      • 时间复杂度
      • 总结
    • 47.全排列Ⅱ
      • 思路
        • 树形图
      • 完整版
      • 时间复杂度
      • 总结

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]]

思路

本题的nums中没有重复元素,因此求集合不需要去重的操作。

本题是排列,排列是强调元素顺序的!之前的题目基本都可以归类为组合问题,组合并不强调元素顺序。

在排列问题中,我们需要用used数组来标记使用过的元素,避免重复取到同一个元素,和组合里的startIndex不同,此时是不需要startIndex的,因为遍历到后面还是需要从0开始。

但是我们需要标记已经取过的元素来看后面的元素取什么,所以需要used数组标记已经选择过的元素

树形图

通过树形图很容易发现,排列和组合问题的区别是,排列是记录当前遍历过的元素,然后这个分支没遍历过的元素,也就是used对应下标0的元素,都需要再遍历一遍

在这里插入图片描述

used数组的作用

排列问题中的used数组,实际上就是看这个分支取过了哪些元素,只要取过的元素别重复取就可以了,前面的元素这个分支没遍历,还是要继续遍历。

伪代码

  • 每个分支都要传入used
void backtracking(vector<int>&path,vector<vector<int>>&result,vector<int>&nums,vector<int>&used){
    //终止条件:收集的path大小和nums大小相等
    if(path.size()==nums.size()){
        //叶子节点收集结果
        result.push_back(path);
        return;
    }
    
    //单层搜索,i从0开始,而不是startIndex,因为每次搜索都从头开始,不是used取过的就行
    for(int i=0;i<num.size();i++){
        //如果这个元素取过了,continue;
        if(used[i]==1){
            continue;
        }
        path.push_back(nums[i]);
        used[i] += 1;
        //递归
        backtracking(path,result,nums,used);
        //回溯
        used[i] -= 1;
        path.pop_back();
    }
    
}

完整版

class Solution {
public:
    void backtracking(vector<int>&path,vector<vector<int>>&result,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;
            }
            path.push_back(nums[i]);
            used[i]+=1;
            //递归
            backtracking(path,result,nums,used);
            //回溯
            path.pop_back();
            used[i]-=1;
        }
        
    }
    vector<vector<int>> permute(vector<int>& nums) {
        //先定义一个和nums大小相等的下标计数数组
		vector<int>used(nums.size(),0);
        vector<int>path;
        vector<vector<int>>result;
        //传入函数
        backtracking(path,result,nums,used);
        return result;
        
    }
};

时间复杂度

本题的时间复杂度为O(n!)

这个问题要求生成一个集合的所有可能排列,总共有**n!**个排列,其中n是数组的大小。在这个问题中,解决方案是通过回溯法,对数组中的每一个元素,进行选择或不选择的操作,进行深度优先遍历,直到遍历完所有可能的路径。

对于空间复杂度,由于需要存储所有的排列,最坏的情况是需要存储n!个排列,因此空间复杂度也是O(n!)

总结

排列问题的不同:

  • for循环遍历,每次都是从0开始
  • 终止条件是path的大小和原数组相同才停下
  • 需要used数组在每个分支path里面,记录这个分支遍历了多少数字,每个分支path里所有数字都要遍历一遍

47.全排列Ⅱ

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

思路

因为本题给出的是包含重复数字的序列 nums,因此涉及到去重的问题。

树形图

本题的去重逻辑和之前用排序+used数组的逻辑是一样的。也是树层去重,树枝不去重。

在这里插入图片描述

完整版

class Solution {
public:
    void backtracking(vector<int>&path,vector<vector<int>>&result,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(i>0&&nums[i]==nums[i-1]&&used[i-1]==0){
                continue;
            }
            //这个数字在当前分支遍历过了,也跳过
            if(used[i]!=0){
                continue;
            }
            path.push_back(nums[i]);
            used[i] += 1;
            //递归
            backtracking(path,result,nums,used);
            //回溯
            path.pop_back();
            used[i] -= 1;
        }
        
    }
    vector<vector<int>> permuteUnique(vector<int>& nums) {
        //定义used并初始化
        vector<int>used(nums.size(),0);
        //排序
        sort(nums.begin(),nums.end());
        
        vector<int>path;
        vector<vector<int>>result;
        backtracking(path,result,nums,used);
        
        return result;
    }
};

时间复杂度

本题的时间复杂度也是O(n!)

这个问题是要生成一个包含重复元素的集合的所有可能排列,并且要避免重复的排列。本题解决方案是先对数组进行排序,然后使用一个标记数组used来跳过重复的元素。

虽然在这个问题中有重复的元素,但实际上并没有减少需要遍历的排列的数量。所以,时间复杂度仍然是O(n!)。空间复杂度也是O(n!),和全排列一样。

总结

涉及到去重的回溯问题,一定要画树形图标出used,树形图画出来了逻辑就清楚了。

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

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

相关文章

C#和LABVIEW的对决:哪种上位机编程语言更适合你?

今天&#xff0c;我们将谈论主流的上位机编程语言。你听说过C#和LABVIEW吗&#xff1f;它们是的上位机编程语言&#xff0c;C#作为自动化主流编程语言特别受欢迎&#xff0c;LABVIEW用于自动化测试&#xff0c; 首先&#xff0c;我们来了解C#语言。C#是一种文本语言&#xff0c…

2023年江西省研究生数模竞赛植物的多样性

2023年江西省研究生数模竞赛 植物的多样性 原题再现 植物作为食物链中的生产者&#xff0c;通过光合作用吸收二氧化碳&#xff0c;制造氧气&#xff0c;同时为其他生物提供食物和栖息地&#xff0c;支持它们的生存。植物在生态系统中还起到防止水土流失、缓解温室效应等作用。…

新手小白编程利器!Debug 断点调试工具IDEA

前言 很多新手小白在学习的时候总会遇到一个问题&#xff1a; 我们一运行程序&#xff0c;只能看到程序最后的结果&#xff0c;但是这个程序究竟是怎么一步步运行出这样的结果呢&#xff1f;如果有一个工具能够让我们看到我们程序的执行流程该有多好~ 这就需要用到新手小白编程…

modbus转MQTT网关支持自定义JSON格式

在工业自动化系统中&#xff0c;Modbus是一种非常常见的通信协议&#xff0c;而OPC UA则是近年来兴起的一种新型通信协议。由于各种设备之间使用的通信协议不尽相同&#xff0c;因此需要一种能够实现多种协议转换的网关产品。BL110网关就是一款能够实现Modbus到OPC UA转换的产品…

硬件设计-PLL篇(下)

目录 概要 整体架构流程 技术名词解释 技术细节 1.环路滤波器采用有源滤波器还是无源滤波器&#xff1f;、 2.如何设计 VCO 输出功率分配器&#xff1f;、 3.如何设置电荷泵的极性&#xff1f; 4.锁定指示电路如何设计&#xff1f; 小结 概要 提示&#xff1a;这里可以添加技术…

学习Spring的补充

《JavaEE 框架整合开发入门到实践 》这本书还是太浅了 &#xff0c;需要补充一些基本的知识。 首先修改一下快捷键&#xff0c;使得可以像eclipse一样使用alt/ 快速补全代码。 参考博客&#xff1a; (33条消息) IDEA 设置代码提示或自动补全的快捷键_idea补全提示_thirty.st…

【Java核心技术】面向对象编程

面向对象编程 1、面向过程与面向对象面向过程(POP)与面向对象(OOP)面向对象的三大特征面向对象的思想概述 2、Java语言基本元素&#xff1a;类和对象类和对象类和对象的使用&#xff08;面向对象思想落地的实现&#xff09;对象的创建和使用&#xff1a;内存解析 3、类的成员之…

【瑞萨RA6系列】CoreMark移植完全指南——UART输出和SysTick计时

一、CoreMark简介 什么是CoreMark&#xff1f; 来自CoreMark首页的解释是&#xff1a; CoreMark is a simple, yet sophisticated benchmark that is designed specifically to test the functionality of a processor core. Running CoreMark produces a single-number scor…

tomcat进程注入

跟随上一篇《java进程注入》 这里使用memShell https://github.com/rebeyond/memShell 将agent.jar和inject.jar放到tomcta的web目录下 然后输入命令注入 效果&#xff1a; 注入成功后 可以看到agent.jar文件为了防止发现&#xff0c;自动清除&#xff0c;而且重启电脑之后&…

【Python数据分析】Python中axis的理解

axis用来为超过一维的数组定义属性。 理解时从数据变化的方向入手&#xff01; 以二维数据为例&#xff0c;在二维数据中&#xff0c;1表示横轴&#xff0c;方向从左到右&#xff1b;0表示纵轴&#xff0c;方向从上到下从数轴的方向入手&#xff0c;理解数据变化&#xff0c;a…

测试这碗饭,你还拿得稳吗?

今年测试行业格外寒冷&#xff0c;大部分人为了糊口饭吃&#xff0c;紧紧地捂住了本来已经很嫌弃的饭碗&#xff0c;以便挺过寒冬迎接春天。 公司天天加班&#xff0c;新出了各种扣款制度&#xff0c;为了上老下小我忍了。 2022年度的绩效&#xff0c;2023年都要过完了&#xf…

Windows同时安装两个版本JDK,并实现动态切换

1、载安装两个版本的JDK 安装后&#xff0c;默认路径C:\Program Files\Java。 实际上JDK8有两个包一个jdk1.8.0_311&#xff0c;一个jre1.8.0_311。 JDK11只有一个jdk-11.0.16.1。 2、系统环境配置 设置JAVA_HOME 在环境变量中选中Path&#xff0c;点击编辑 点击新建&…

DARAZ使用虚拟信用卡购物教程

Daraz为阿里巴巴南亚电商平台&#xff0c;市场覆盖巴基斯坦、孟加拉、斯里兰卡、尼泊尔和缅甸超过5亿人口级别市场&#xff0c;是南亚地区最受欢迎的在线购物网站&#xff0c;购物APP NO.1。 注册一个DARAZ的买家账号。 找到需要购买的商品&#xff0c;点击Buy Now进行购买 填…

Sip通话,qq通话,微信通话,普通的通话的条件和过程描述

SiP通话 SIP电话是基于SIP&#xff08;Session Initiation Protocol&#xff0c;会话初始化协议&#xff09;协议实现的通信。SIP是一种应用层协议&#xff0c;用于建立、修改和终止多媒体会话&#xff0c;如语音通话、视频通话等。SIP电话通过SIP协议进行信令交换和媒体流传输…

【MySQL学习笔记】(二)MySQL操作库基础

库的操作 1 创建数据库2 关于字符集和校验规则2.1 查看系统字符集以及校验规则2.2 查看数据支持的字符集2.3 查看数据库支持的字符集校验规则3 删除数据库4 查看并使用数据库5 修改数据库6 查看连接情况7 备份和恢复 1 创建数据库 1&#xff09;创建数据库 在学习笔记&#xf…

ChatGLM-6b本地安装手把手教学

什么是ChatGLM-6B ChatGLM-6B 是一个开源的、支持中英双语的对话语言模型&#xff0c;基于 General Language Model (GLM) 架构&#xff0c;具有 62 亿参数。结合模型量化技术&#xff0c;用户可以在消费级的显卡上进行本地部署&#xff08;INT4 量化级别下最低只需 6GB 显存&…

Redis【入门篇】---- Redis的Java客户端-SpringDataRedis

Redis【入门篇】---- Redis的Java客户端-SpringDataRedis 1. 快速入门1. 导入pom坐标2. 配置文件3. 测试代码 2. 数据序列化器3. StringRedisTemplate4. Hash结构操作 SpringData是Spring中数据操作的模块&#xff0c;包含对各种数据库的集成&#xff0c;其中对Redis的集成模块…

网络安全|渗透测试入门学习,从零基础入门到精通—静态分析技术详解

目录 前言 1、文件类型分析 2、反汇编引擎 2.1、OllyDbg的ODDisasm 2.2、BeaEngine 2.3、Udis86 2.5、AsmJit 2.6、Keystone 2.7、小结 前言 用高级语言编写的程序有两种形式。一种程序是被编译成机器语言在CPU上执行的&#xff0c;例如Visual C。机器语言与汇编语言几乎…

【Docker】docker启动oracle11g并初始化数据,部署和使用

前提&#xff1a;已经在docker中安装好Oracle 1.启动docker&#xff1a; docker run --name oracle11 -p 1521:1521 -e ORACLE_ALLOW_REMOTEtrue -e ORACLE_PWDoracle -d oracleinanutshell/oracle-xe-11g出现问题&#xff0c;请查看&#xff1a;Exited 139解决Window下docke…

web漏洞-反序列化之JAVA全解(38)

首先第一个就是概念。第二个是他的利用&#xff0c;一个好用的工具ysoserial&#xff0c;主要用来生成工具的paload&#xff0c;修复大差不差。 #概念&#xff1a;我们有时候需要保存某一个对象的信息&#xff0c;会进行一些操作&#xff0c;类似于反序列化&#xff0c;序列化…