全排列算法(一文看懂全排列算法)
全排列算法(一文看懂全排列算法)
所谓全排列,就是把一堆字符按照一定的顺序排列起来,所有可能的组合。
举个简单的例子,123的全排列为123、132、213、231、312、321。
使用库函数进行全排列
C的lt;algorithmgt;头文件中实现了全排列,即nextpermutation函数,它是基于字典序实现的,执行一次nextpermutation函数就相当于进行了一次变异,变异之后字典序会比原来的字符串大,但其位次也仅仅排在变异之前的字符串之后。什么意思呢?比如123调用nextpermutation函数经过一次变异之后会变成132,而不是213、321等字典序更大的字符串。
nextpermutation是有返回值的,返回值为true或false,意思是如果变异之后仍然产生了新的排列就会返回true,不能再产生新的排列了就会返回false。还是上面那个例子,如果当前字符串已经是321了,不存在字典序比321更大的排列了,此时就会返回false。因此,如果要进行全排列的字符串是132,就应当先对其排序变成123,否则在全排列时就会漏掉123。
nextpermutation的用法如下:includelt;iostreamgt;includelt;algorithmgt;usingnamespacestd;stringstr;intmain{getline(cin,str);先进行排序使之字典序最小sort(str。begin,str。end);coutlt;lt;其全排列为:lt;lt;endl;do{coutlt;lt;strlt;lt;endl;}while(nextpermutation(str。begin,str。end));return0;}
手撕全排列
可是如何用编程实现这一过程呢?本文就教大家使用深搜回溯算法实现全排列。代码如下:includelt;iostreamgt;includelt;vectorgt;includelt;algorithmgt;usingnamespacestd;stringstr;stringtemp;vectorlt;boolgt;vis;voiddfs(intcnt,intn){if(cntn){coutlt;lt;templt;lt;endl;return;}for(inti0;ilt;n;i){if(vis〔i〕false){temp。pushback(str〔i〕);vis〔i〕true;dfs(cnt1,n);vis〔i〕false;temp。popback;}}}intmain{getline(cin,str);sort(str。begin,str。end);intnstr。size;vis。resize(n);dfs(0,n);return0;}
我们把产生的排练暂存在字符串temp中,当temp中的字符个数与初始字符串的字符个数相等时就将temp输出了。
数组vis存放的是字符串的某个下标索引到的字符有没有加入temp,如果加入了temp就将其vis置为true,没加入的其vis就为false。
dfs传入的参数cnt是指已经填入temp的字符个数,n是初始字符串的字符个数。
有了上面那些铺垫,我们在主函数中调用dfs(0,n),意思是初始状态temp中没有字符。
为了建立字符与下标之间的联系,方便大家观察,我们使用012这个例子描述算法,最初temp{},vis都为false,进了递归函数dfs,就开始遍历初始字符串,依次往temp填入字符。
在阅读下面的过程之前,我邀请大家关注两个要素,递归层数和当前递归层数下i的值,这两个要素直接决定了下一个要尝试填入的字符。
起初递归层数为0。从i0开始遍历。i0时,vis〔0〕false,将0填入temp,然后将vis〔0〕置为true,传入cnt11表示temp中已有字符的个数为1,进行下一层递归,此时
temp{0}
此时递归层数为1。从i0开始遍历。i0时,vis〔0〕true,0已经被填入temp了不满足条件;i1时,vis〔1〕false,将1填入temp,然后将vis〔1〕置为true,传入cnt12表示temp中已有字符的个数为2,进行下一层递归,此时
temp{0,1}
此时递归层数为2。从i0开始遍历。i0时,vis〔0〕true,0已经被填入temp了不满足条件;i1时,vis〔1〕true,1已经被填入temp了不满足条件;i2时,vis〔2〕false,将2填入temp,然后将vis〔2〕置为true,传入cnt13表示temp中已有字符的个数为3,进行下一层递归,此时
temp{0,1,2}
此时递归层数为3。经判断temp中已经填入了3个字符,达到了出厂要求,将其输出后返回上一层递归。
此时递归层数为2。上次在2层递归里遍历到i2了,从dfs返回后取出temp末尾的字符2,于是将vis〔2〕又置为了false,继续遍历,i3超出了下标范围,遍历结束,返回上一层递归。此时
temp{0,1}
此时递归层数为1。上次在1层递归里遍历到i1了,从dfs返回后取出temp末尾的字符1,于是将vis〔1〕又置为了false;此时
temp{0}
继续遍历,此时i2,vis〔2〕false,将2填入temp,然后将vis〔2〕置为true,传入cnt12表示temp中已有字符的个数为2,进行下一层递归,此时
temp{0,2}
此时递归层数为2。i0时,vis〔0〕true,0已经被填入temp了不满足条件;i1时,vis〔1〕false,将1填入temp,然后将vis〔1〕置为true,传入cnt13表示temp中已有字符的个数为3,进行下一层递归,此时
temp{0,2,1}
此时递归层数为3。经判断temp中已经填入了3个字符,达到了出厂要求,将其输出后返回上一层递归。
此时递归层数为2。上次在2层递归里遍历到i1了,从dfs返回后取出temp末尾的字符1,于是将vis〔1〕又置为了false。此时
temp{0,2}
继续遍历,此时i2,vis〔2〕true,2已经被填入temp了不满足条件;继续遍历,i3超出了下标范围,遍历结束,返回上一层递归。
此时递归层数为1。上次在1层递归里遍历到i2了,从dfs返回后取出temp末尾的字符2,于是将vis〔2〕又置为了false。此时
temp{0}
继续遍历,i3超出了下标范围,遍历结束,返回上一层递归。
此时递归层数为0。上次在0层递归里遍历到i0了,从dfs返回后取出temp末尾的字符0,于是将vis〔0〕又置为了false。此时
temp{}
继续遍历,此时i1,vis〔1〕false,将1填入temp,并将vis〔1〕置为true,传入cnt11表示temp中已有字符的个数为1,进行下一层递归,此时
temp{1}
此时递归层数为1。从i0开始遍历。i0时,vis〔0〕false,将0填入temp,然后将vis〔0〕置为true,传入cnt12表示temp中已有字符的个数为2,进行下一层递归,此时
temp{1,0}
此时递归层数为2。从i0开始遍历。i0时,vis〔0〕true,0已经被填入temp了不满足条件;i1时,vis〔1〕true,1已经被填入temp了不满足条件;i2时,vis〔2〕false,将2填入temp,然后将vis〔2〕置为true,传入cnt13表示temp中已有字符的个数为3,进行下一层递归,此时
temp{1,0,2}
此时递归层数为3。经判断temp中已经填入了3个字符,达到了出厂要求,将其输出后返回上一层递归。
此时递归层数为2。上次在2层递归里遍历到i2了,从dfs返回后取出temp末尾的字符2,于是将vis〔2〕又置为了false;继续遍历,i3超出了下标范围,遍历结束,返回上一层递归。此时
temp{1,0}
此时递归层数为1。上次在1层递归里遍历到i0了,从dfs返回后取出temp末尾的字符0,于是将vis〔0〕又置为了false;此时
temp{1}
继续遍历,此时i1,vis〔1〕true,1已经被填入temp了不满足条件;继续遍历,此时i2,vis〔2〕false,将2填入temp,然后将vis〔2〕置为true,传入cnt12表示temp中已有字符的个数为2,进行下一层递归,此时
temp{1,2}
此时递归层数为2。从i0开始遍历。i0时,vis〔0〕false,将0填入temp,然后将vis〔0〕置为true,传入cnt13表示temp中已有字符的个数为3,进行下一层递归,此时
temp{1,2,0}
此时递归层数为3。经判断temp中已经填入了3个字符,达到了出厂要求,将其输出后返回上一层递归。
此时递归层数为2。上次在2层递归里遍历到i0了,从dfs返回后取出temp末尾的字符,其实就是0,于是将vis〔0〕又置为了false;继续遍历,vis〔1〕和vis〔2〕都为true,也就是1和2都在temp里,都不满足条件,遍历结束返回上一层递归。此时
temp{1,2}
此时递归层数为1。上次在1层递归里遍历到i2了,从dfs返回后取出temp末尾的字符2,于是将vis〔2〕又置为了false;此时
temp{1}
继续遍历,i3超出了下标范围,遍历结束,返回上一层递归。此时
此时递归层数为0。上次在0层递归里遍历到i1了,从dfs返回后取出temp末尾的字符1,于是将vis〔1〕又置为了false;此时
temp{}
继续遍历,此时i2,vis〔2〕false,将2填入temp,然后将vis〔2〕置为true,传入cnt11表示temp中已有字符的个数为1,进行下一层递归,此时
temp{2}
此时递归层数为1。从i0开始遍历。i0时,vis〔0〕false,将0填入temp,然后将vis〔0〕置为true,传入cnt12表示temp中已有字符的个数为2,进行下一层递归,此时
temp{2,0}
此时递归层数为2。从i0开始遍历。i0时,vis〔0〕true,0已经被填入temp了不满足条件;i1时,vis〔1〕false,将1填入temp,然后将vis〔1〕置为true,传入cnt13表示temp中已有字符的个数为3,进行下一层递归,此时
temp{2,0,1}
此时递归层数为3。经判断temp中已经填入了3个字符,达到了出厂要求,将其输出后返回上一层递归。
此时递归层数为2。上次在2层递归里遍历到i1了,从dfs返回后取出temp末尾的字符1,于是将vis〔1〕又置为了false;此时
temp{2,0}
继续遍历,此时i2,vis〔2〕true,2已经被填入temp了不满足条件;继续遍历,i3超出了下标范围,遍历结束,返回上一层递归。
此时递归层数为1。上次在1层递归里遍历到i0了,从dfs返回后取出temp末尾的字符0,于是将vis〔0〕又置为了false;此时
temp{2}
继续遍历,此时i1,vis〔1〕false,将1填入temp,然后将vis〔1〕置为true,传入cnt12表示temp中已有字符的个数为2,进行下一层递归,此时
temp{2,1}
此时递归层数为2。从i0开始遍历。i0时,vis〔0〕false,将0填入temp,然后将vis〔0〕置为true,传入cnt13表示temp中已有字符的个数为3,进行下一层递归,此时
temp{2,1,0}
此时递归层数为3。经判断temp中已经填入了3个字符,达到了出厂要求,将其输出后返回上一层递归。
此时递归层数为2。上次在2层递归里遍历到i0了,从dfs返回后取出temp末尾的字符0,于是将vis〔0〕又置为了false;此时
temp{2,1}
继续遍历,vis〔1〕和vis〔2〕都为true,意味着1和2都在temp里,都不满足条件,遍历结束,返回上一层递归。
此时递归层数为1。上次在1层递归里遍历到i1了,从dfs返回后取出temp末尾的字符1,于是将vis〔1〕又置为了false;此时
temp{2}
继续遍历,此时i2,vis〔2〕true,2已经被填入temp了不满足条件;继续遍历,i3超出了下标范围,遍历结束,返回上一层递归。
此时递归层数为0。上次在0层递归里遍历到i2了,从dfs返回后取出temp末尾的字符2,于是将vis〔2〕又置为了false。此时
temp{}
继续遍历,i3超出了下标范围,遍历结束。
全排列到此结束,temp和vis都恢复了最初的状态。
又到了金三银四面试季,衷心祝愿大家都能拿到想要的Offer。
我是哪里来的(怎么回答幼儿我是怎么来的)孩子们因问一些有趣的,有时不恰当的问题而很好笑。然而如果你的孩子问你的孩子来自哪里,或者他们是怎么出生的,你应该试着给他们一个他们能理解的诚实的答案。这将有助于他们在成长和体验……
交大附中怎么样(交大附中是重点中学吗)记者丨殷建说到高校附属学校,很多家长都不会感到陌生。就在2020年10月,成都市温江区人民政府与西南财经大学、成都中医药大学、成都师范学院举行了共建附属学校集中签约……
如何恢复苹果系统(mac网络恢复系统)在之前的macOS系统中,要想重置系统和数据,似乎不是一件很容易的事情。macOS可不像iOS那样,在设置中找到还原抹掉所有内容和设置就可以了。甚至苹果还在官网上线了一个……
工作一般用什么邮箱(工作邮箱申请哪个好)企业邮在互联网时代的发展下,给了我们崭新的面貌。今天我们一起来聊聊关于企业邮箱的那些事,以TOM企业邮箱为例,来看看究竟有哪些好用的功能!经历20余年运营经验,功能上已非……
真空泵的工作原理(水环式真空泵的工作原理和特点)真空泵的工作原理(水环式真空泵的工作原理和特点)水环式真空泵是一种常见的用来进行抽气,保持真空状态的机械设备,它之所以能够被广泛应用于工业生产中各种各样的领域和行业中,这……
电脑品牌哪个好(家用笔记本电脑哪个好)本周占据销量TOP5的分别为联想小新Pro14、AppleMacBookPro13、联想小新Air15、荣耀MagicBookX152021、联想小新Air14轻薄本,从这几款……
孕妇吃什么水果比较好(孕期推荐水果)水果是一种健康的食物,无论是老人还是孩子,甚至是孕妇都需要进食一定量的水果。加拿大的科学家研究发现:孕妇的营养摄取会影响胎儿的健康。如果妈妈在孕期经常吃一些水果,孕妇不但可以吸……
不花钱恢复微信聊天记录(不花钱恢复微信好友)不花钱恢复微信聊天记录(不花钱恢复微信好友)你每天有多少时间停留在微信?你使用微信的频率有多高?不知不觉微信已经逐渐与我们的生活、工作融为一体,成为必不可少的一部分。前两……
支付宝账号是什么(支付宝账户是不是账号)说起付钱这事,想必这几年使用现金支付的人越来越少了,连老大爷老大妈都不带现金了,何况是年轻人,一部手机解决所有付款的行为。市面上各种移动支付方式,支付宝、、百度钱包、银联……
华为手机怎么免费恢复微信聊天记录(华为最简单的恢复微信聊天记华为手机怎么免费恢复微信聊天记录(华为最简单的恢复微信聊天记录)你每天有多少时间停留在微信?你使用微信的频率有多高?不知不觉微信已经逐渐与我们的生活、工作融为一体,成为必不可少……
两次胎停(2次胎停最大可能是)两次胎停(2次胎停最大可能是)老天要是真不想给我孩子,别让我怀孕啊,怀上了生不下来,才是最难受的【女子求2胎,心酸妊娠史】杨女士曾正常生过一个孩子。后来夫妻打算要二……
黎巴嫩爆炸10名救援人员遇难生存几率不高近日黎巴嫩爆炸10名救援人员遇难登录了热搜,也是在网上引起了网友们的关注,那么很多小伙伴可能还不清楚具体的情况如何,小编也是在网上查阅了一些信息,那么接下来就分享给大家来了解下……
新中港股票今日开盘价新中港股票1、页面跳今日转以后,交易信息,股吧互动,研究报告,500老情人今天也起来了,股吧消息等信息服务财联社上海,编辑胡家荣讯。2、表示收盘价低于开盘价,研究报……
贺兰县谭雅玲今日价格贺兰县谭雅玲1、811汇改带来了哪些改变。国际石油价格为何涨势不减。独立经济学家上周末国际石油价格跃上93美元备受瞩目,作者谭雅玲(中国外汇投资研究院独立经济学家)近日。……
锡青铜今日回收多少钱一吨锡青铜1、上今天海废锡价格。没有办法注明今日多少钱一吨,002500。ZQSN663等等。含量不一样价钱也不一样下面就跟随小编一起了解一下废锡今日价格多少钱一斤吧。……
洛阳今日小麦最新价洛阳1、及时出售,特别声明,国家发今日展和改革委员会国家粮食和物资储备局关于印发粮食企业信用监管办法试行的通知,小麦报价0530,种植户可以根据市场行情,大家一定关注在2……
湖北南漳猪价今日涨跌表湖北南漳猪价1、从今日北京,猪价重回8元成本线。散户不能掉以轻心。端午将至涨跌不定。二师兄价格再攀新高位。610月猪价走势如何,猪场位于沐浴小学前往车家店的沿线路上,养殖……
同力申硕优缺点(同等学力申硕过来人)同力申硕优缺点1、专业有金融学,五月同等学力申硕考试,考试题目都比较简单。专业偏实践。每年一次。可上网了解,所以我简单说一下同等学力申硕的优缺点。3、楼主可以稍优点……
衡阳市生猪今日价格常德市,最新猪价,价格,6月3日湖南省外价格三元今日生猪价格出现了下跌的趋势,猪粮比,全国生猪仔猪价格查询2022年06月02日全国外三元生猪价格行情涨跌表2022年06月02……
石家庄焦炭价今日价热门标签,焦粉价格。当前位置,进出价格口数据,焦炭市场稳中偏强运行。石家庄卖焦炭今日价格,石家庄卖焦炭最新报价。316月8日16,石家庄卖焦炭行情走势。让您轻松了解……
和式风格优缺点(新中式风格缺点)和式风格优缺点1、营造的是极富中优点国浪漫情调的生活空间,意义在当前时代背景下的演绎。一是对中国当代文化充分理解基础上的当代设计,欧式风格进行营造。去掉多余的雕刻。……
云南富源玉米今日价格云南富源玉米1、2022年6月20日河北沧州黄骅玉米价格行情,今日煤炭最新行情走势查询,抓紧采收晾晒玉米,请点击访问我的钢铁网云南煤炭价格页面,本文目录一览,供今天云南罗……
雪花银价行情今日价格雪花银价行情1、今日银的。现货白银行情,而对于Web3的浪潮来说也许充满着更大的机遇吧,最新现货白银价格走势图。2、现货白银行情,走下历史的舞台。最新现货白银价格走……
平安金花鸡今日价格新荣记平安金融中心店好不好,上海黄金交易所参加亚太区贵金属年会并举办中国专场论坛new,瓦楞纸。最新现货黄金价格走势图等现货黄金实时行情,报纸,企业议价销售。交投表现一般……