面试经典算法1:DFS
一、前言
1、题目描述和代码仅供参考,如果有问题欢迎指出
2、解题代码采用acm模式(自己处理输入输出),不采用核心代码模式(只编程核心函数)
3、解题代码采用C++语言(ai一键翻译任意语言,或者cpp转Java等任意语言)
二、题目说明
题目:
给你一个整数集合 nums ,按任意顺序 返回它所有不重复的全排列。
举例:
输入:nums = [1,2,3]
输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
三、DFS回溯法(递归编程实现)
解题思路:
定义一个f()函数求可行的全排列解,如果到叶子节点时该路径可行就记录,否则回溯求解;
f(123) = 1 + f(23),
f(23)= 2 + f(3),
f(3)= 3
解题代码:
#include <iostream>
#include <vector>using namespace std;// end参数可以用nums.size()代替,但是这里为了方便理解所以加上
void permute(vector<int>& nums, int start, int end, vector<vector<int>>& result) {if (start == end) {result.push_back(nums);//到达叶子节点,记录结果return;}for (int i = start; i <= end; i++) {swap(nums[start], nums[i]);// 将第i个元素和第start个元素交换位置,固定第start个元素permute(nums, start + 1, end, result);// 递归调用,固定[start+1, end]这个区间的元素swap(nums[start], nums[i]); // 回溯恢复原来的数组顺序,用于下一次循环}
}int main() {vector<int> nums = { 1, 2, 3 };vector<vector<int>> result;permute(nums, 0, nums.size() - 1, result);for (auto& v : result) {for (int num : v) {cout << num << " ";}cout << endl;}return 0;
}
四、有重复元素时的解法:STL库函数实现
题目说明:
当 nums有重复元素时,如果采用回溯法 ,nums有重复元素就用hash记录被选择的数字,如果已经被选择过就跳过,这当然可以解决问题,不过我们有更优雅的解法,那就是STL中的库函数,这里写出来是因为面试官可能不让你直接调库函数;
解题思路:
两个函数next_permutation和prev_permutation,分别用于生成下一个排列和上一个排列。
next_permutation函数的工作原理是找到从右到左第一个升序对(即nums[i] < nums[i+1]),然后找到这个升序对右边第一个大于它的元素(即nums[j] > nums[i]),交换这两个元素的位置,最后将升序对右边的元素反转。这样就得到了下一个排列。
prev_permutation函数的工作原理类似,只是它是找升序对,然后找到这个升序对左边第一个小于它的元素,交换这两个元素的位置,最后将升序对左边的元素反转。这样就得到了上一个排列。
在main函数中,首先调用prev_permutation函数生成所有的上一个排列,然后调用next_permutation函数生成所有的下一个排列。这样就可以得到所有的排列,而且由于next_permutation函数会跳过所有重复的排列,所以可以避免重复。
原理很详细的一篇文章:https://blog.csdn.net/myRealization/article/details/104803834
解题代码:
#include <iostream>
#include <vector>
#include <algorithm>using namespace std;bool next_permutation(vector<int>& nums) {int i = nums.size() - 2;while (i >= 0 && nums[i] >= nums[i + 1]) --i;if (i == -1) return false;int j = nums.size() - 1;while (nums[j] <= nums[i]) --j;swap(nums[i], nums[j]);reverse(nums.begin() + i + 1, nums.end());return true;
}bool prev_permutation(vector<int>& nums) {int i = 0;while (i < nums.size() - 1 && nums[i] <= nums[i + 1]) ++i;if (i == nums.size() - 1) return false;int j = nums.size() - 1;while (nums[j] >= nums[i]) --j;swap(nums[i], nums[j]);reverse(nums.begin(), nums.begin() + i + 1);return true;
}int main() {vector<int> nums = {1, 2, 3};vector<vector<int>> result;while (prev_permutation(nums)){};//O(n)时间复杂度,而sort是nlog n do {result.push_back(nums);} while (next_permutation(nums));for(auto i: result){for(auto j : i)cout << j << " ";cout << endl;}return 0;
}
如此时间复杂度就是O(n),空间复杂度O(1),如果这样面试还是过不了的话,那就不是你的问题了…
迭代器版本实现
template<typename Iterator>
bool myNextPermutation(Iterator start, Iterator end) { //[start,end)Iterator cur = end - 1, pre = cur - 1; //pre指向partitionNumber while (cur > start && *pre >= *cur) --cur, --pre; //从右到左进行扫描,发现第一个违背非递减趋势的数字if (cur <= start) return false; //整个排列逆序, 不存在更大的排列 //从右到左进行扫描,发现第一个比partitionNumber大的数for (cur = end - 1; *cur <= *pre; --cur); //cur指向changeNumber std::iter_swap(pre, cur);std::reverse(pre + 1, end); //将尾部的逆序变成正序 return true;
}template<typename Iterator>
bool myPrevPermutation(Iterator start, Iterator end) { //[start,end)Iterator cur = end - 1, pre = cur - 1; //pre指向partitionNumber while (cur > start && *pre <= *cur) --cur, --pre; //从右到左进行扫描,发现第一个违背非递增趋势的数字if (cur <= start) return false; //整个排列逆序, 不存在更小的排列 //从右到左进行扫描,发现第一个比partitionNumber小的数for (cur = end - 1; *cur >= *pre; --cur); //cur指向changeNumber std::iter_swap(pre, cur);std::reverse(pre + 1, end); //将尾部的逆序变成正序 return true;
}
1 2 3
从小到大排序的是最小的排列,从大到小排序是最大的排列。
求f(123)的排列,实际上是确定了第1个数以后求len-1个数的排列即 1 + f(23),依次类推毫无疑问这会想到dfs;
然而还有更好的解法
举例 1 3 2,求增长幅度最小下一个排列,
32为逆序不可能减小,所以要换1,1和其右侧第一个大于1的数互换
互换之后此时后半部分是逆序,倒序交换数字的右侧以后就是最小的排列
精简步骤就是
next
1、从右到左找升序对的位置
2、右侧找第一个大于升序对的位置
3、交换,并倒序升序对右侧
prev
1、从左到右找降序对的位置
2、左侧找第一个小于降序对的位置
3、交换,并倒序降序对左侧
为什么不会有重复序列?
因为next_permutation()函数可以生成给定序列的下一个字典序排列。它通过在序列中查找第一个违反字典序排列的元素,并将其交换到序列末尾来实现这一点。
然后,它将序列中剩余的元素重新排序,以生成下一个字典序排列。
由于next_permutation()函数是基于字典序排列的,因此它不会生成重复的序列。这是因为每个元素都只能出现在其原始位置或者在其后面的某个位置上,而
不会出现在其前面的位置上。
举个例子,假设我们有一个序列 [1, 2, 3],它的下一个字典序排列是 [1, 3, 2]。如果我们再次调用next_permutation()函数,它会找到下一个字典序排列,
即 [2, 1, 3]。这个过程会一直持续下去,直到我们回到原始序列为止。
因此,next_permutation()函数可以确保生成的排列是唯一的,不会有重复的序列。
相关文章:
面试经典算法1:DFS
一、前言 1、题目描述和代码仅供参考,如果有问题欢迎指出 2、解题代码采用acm模式(自己处理输入输出),不采用核心代码模式(只编程核心函数) 3、解题代码采用C语言(ai一键翻译任意语言ÿ…...
Windows系统利用cpolar内网穿透搭建Zblog博客网站并实现公网访问内网!
文章目录 1. 前言2. Z-blog网站搭建2.1 XAMPP环境设置2.2 Z-blog安装2.3 Z-blog网页测试2.4 Cpolar安装和注册 3. 本地网页发布3.1. Cpolar云端设置3.2 Cpolar本地设置 4. 公网访问测试5. 结语 1. 前言 想要成为一个合格的技术宅或程序员,自己搭建网站制作网页是绕…...
SmartCode ViewerX VNC 3.11 Crack
SmartCode ViewerX VNC 查看器 ActiveX 轻松地将 VNC 查看器功能添加到您的应用程序中 SmartCode ViewerX VNC Viewer ActiveX 使开发人员可以使用一组直观的 ActiveX 属性和方法完全访问 VNC 查看器功能。借助ViewerX控件,开发人员可以轻松地为其应用程序提供屏幕共…...
傻瓜式Java操作MySQL数据库备份
文章目录 前言存储数据库存储数据表 前言 数据库备份是开发工作中经常要做的事情,好处是mysql提供了一个非常好的命令 mysqldump,直接调用它就可以将数据以sql文件的形式备份出来。但是直接写命令非常不方便,遇到定时备份或者指定备份那么就需…...
redis常用操作命令
日升时奋斗,日落时自省 注:命令区分有点细,择取自己需要的即可 目录 1、单机架构 2、数据库和应用分离 3、分布式基本概念 3.1、应用(Application)/系统(System) 3.2、模块(Module)/组件&…...
pytorch gpu安装
cuda https://blog.csdn.net/qq_51570094/article/details/124148671 https://blog.csdn.net/zxdd2018/article/details/127705627 cudnn https://docs.nvidia.com/deeplearning/cudnn/install-guide/index.html#installlinux-tar 更改cudnn 保证文件目录中只有一个解压后…...
uni跳转页面不缓存上一个页面的方法
一、前言 要实现一个需求,从a页面跳转到b页面,从b页面跳转到c页面,然后按返回,从c页面直接返回a页面(不返回b页面) a->b->c c->a 二、实现方法 前端框架使用的是uni-app,我们修改…...
排序:败者树和置换选择排序(解决外部排序中的优化问题)
1.算法目的(败者树) 解决多路平衡归并带来的问题。 在外部排序中,使用k路平衡归并策略, 选出一个最小元素需要对比关键字(k-1)次, 导致内部归并所需时间增加。(可用“败者树”进行优化) 2.败者树的定义 …...
【超分:光谱响应函数】
Spectral Response Function-Guided Deep Optimization-Driven Network for Spectral Super-Resolution (光谱响应函数引导的深度优化驱动网络光谱超分辨) 高光谱图像(HSI)是许多研究工作的关键。光谱超分辨率(SSR&a…...
IoT 物联网 JavaScript 全栈开发,构建家居环境监控系统实战
智能家居环境监测端到端场景,全栈JavaScript开发,串联Ruff硬件、温湿度和空气质量传感器、阿里云 IoT、Serverless函数计算、百度ECharts可视化、最终以微信小程序形式在微信里实时展示家中实时温度,湿度,PM2.5指数。 01 技术架构…...
jupyter notebook可以打开,但无法打开.ipynb文件,报错500 : Internal Server Error
1、错误信息 2、解决办法 打开Anaconda Promt界面,进入自己的虚拟环境。在命令行输入以下指令: pip install --upgrade nbconvert...
latex图片编号+表格编号
对编号重新自定义 \renewcommand{\thefigure}{数字编号x}重新命名图的编号\renewcommand{\thetable}{数字编号x}重新命名表的编号编号含义 平时看书经常看到“图1.2”这样的编号,含义是第1章的第2幅插图;或者“图1.1.2”,含义是第1章第1节的…...
【1day】用友时空KSOA平台 imagefield接口SQL注入漏洞学习
注:该文章来自作者日常学习笔记,请勿利用文章内的相关技术从事非法测试,如因此产生的一切不良后果与作者无关。 目录...
linux之美
linux系统和window系统区别 Linux和Windows是两个不同的操作系统。Linux是一个开源操作系统,而Windows是一个商业操作系统。 Linux可以访问源代码并根据用户的需求进行修改,而Windows无法访问源代码。 Linux是免费的,而Windows是商业操作系…...
5、超链接标签
5、超链接标签 超链接标签就是我们常说的a标签 <a href"path" target"目标窗口位置">连接文本或图像</a> <!-- href(必填项):连接路径 target:连接在哪个窗口打开?是在新页面打开…...
CCF CSP认证历年题目自练 Day15
CCF CSP认证历年题目自练 Day15 题目一 试题编号: 201709-1 试题名称: 打酱油 时间限制: 1.0s 内存限制: 256.0MB 问题描述: 问题描述 小明带着N元钱去买酱油。酱油10块钱一瓶,商家进行促销…...
APP的收费模式及特点
移动应用(APP)的收费模式多种多样,可以根据开发者的需求、目标受众和应用的性质来选择。以下是一些常见的APP收费模式及其特点,希望对大家有所帮助。北京木奇移动技术有限公司,专业的软件外包开发公司,欢迎…...
opencv: 解决保存视频失败的问题
摘要:opencv能读取视频,但保存视频时报错。 一、首先要确保已经下载了openh264.dll文件,否则保存的视频无法打开,详细可以浏览这个:opencv:保存视频。 二、保存视频时出现一下问题: OpenCV:…...
源码编译安装zstd
目录 1 下载源码https://github.com/facebook/zstd 2 解压 3 在解压后的目录里输入make 4 sudo make install 安装完毕 5 输入whereis zstd 检查安装结果 1 下载源码https://github.com/facebook/zstd 2 解压 3 在解压后的目录里输入make 4 sudo make install 安装完毕…...
LabVIEW开发实时自动化多物镜云计算全玻片成像装置
LabVIEW开发实时自动化多物镜云计算全玻片成像装置 数字病理学领域正在迅速发展,这主要是由于计算机处理能力、数据传输速度、软件创新和云存储解决方案方面的技术进步。因此,病理科室不仅将数字成像用于图像存档等简单任务,还用于远程病理学…...
【Python】 -- 趣味代码 - 小恐龙游戏
文章目录 文章目录 00 小恐龙游戏程序设计框架代码结构和功能游戏流程总结01 小恐龙游戏程序设计02 百度网盘地址00 小恐龙游戏程序设计框架 这段代码是一个基于 Pygame 的简易跑酷游戏的完整实现,玩家控制一个角色(龙)躲避障碍物(仙人掌和乌鸦)。以下是代码的详细介绍:…...
基于当前项目通过npm包形式暴露公共组件
1.package.sjon文件配置 其中xh-flowable就是暴露出去的npm包名 2.创建tpyes文件夹,并新增内容 3.创建package文件夹...
【python异步多线程】异步多线程爬虫代码示例
claude生成的python多线程、异步代码示例,模拟20个网页的爬取,每个网页假设要0.5-2秒完成。 代码 Python多线程爬虫教程 核心概念 多线程:允许程序同时执行多个任务,提高IO密集型任务(如网络请求)的效率…...
vue3+vite项目中使用.env文件环境变量方法
vue3vite项目中使用.env文件环境变量方法 .env文件作用命名规则常用的配置项示例使用方法注意事项在vite.config.js文件中读取环境变量方法 .env文件作用 .env 文件用于定义环境变量,这些变量可以在项目中通过 import.meta.env 进行访问。Vite 会自动加载这些环境变…...
Hive 存储格式深度解析:从 TextFile 到 ORC,如何选对数据存储方案?
在大数据处理领域,Hive 作为 Hadoop 生态中重要的数据仓库工具,其存储格式的选择直接影响数据存储成本、查询效率和计算资源消耗。面对 TextFile、SequenceFile、Parquet、RCFile、ORC 等多种存储格式,很多开发者常常陷入选择困境。本文将从底…...
springboot整合VUE之在线教育管理系统简介
可以学习到的技能 学会常用技术栈的使用 独立开发项目 学会前端的开发流程 学会后端的开发流程 学会数据库的设计 学会前后端接口调用方式 学会多模块之间的关联 学会数据的处理 适用人群 在校学生,小白用户,想学习知识的 有点基础,想要通过项…...
LRU 缓存机制详解与实现(Java版) + 力扣解决
📌 LRU 缓存机制详解与实现(Java版) 一、📖 问题背景 在日常开发中,我们经常会使用 缓存(Cache) 来提升性能。但由于内存有限,缓存不可能无限增长,于是需要策略决定&am…...
(一)单例模式
一、前言 单例模式属于六大创建型模式,即在软件设计过程中,主要关注创建对象的结果,并不关心创建对象的过程及细节。创建型设计模式将类对象的实例化过程进行抽象化接口设计,从而隐藏了类对象的实例是如何被创建的,封装了软件系统使用的具体对象类型。 六大创建型模式包括…...
pikachu靶场通关笔记19 SQL注入02-字符型注入(GET)
目录 一、SQL注入 二、字符型SQL注入 三、字符型注入与数字型注入 四、源码分析 五、渗透实战 1、渗透准备 2、SQL注入探测 (1)输入单引号 (2)万能注入语句 3、获取回显列orderby 4、获取数据库名database 5、获取表名…...
【UE5 C++】通过文件对话框获取选择文件的路径
目录 效果 步骤 源码 效果 步骤 1. 在“xxx.Build.cs”中添加需要使用的模块 ,这里主要使用“DesktopPlatform”模块 2. 添加后闭UE编辑器,右键点击 .uproject 文件,选择 "Generate Visual Studio project files",重…...
