全排列
2016-03-09 16:51
543 查看
参考于:【STL】next_permutation的原理和使用
给定一个数列,如何得到它的全排列?
例如1 2 3,它的全排列是123,132,213,231,312,321。
全排列的关键在于,给定某一数列,能从该数列推出“下一个”数列。
那么如何找“下一个”数列呢?
找“下一个”数列的算法思路描述如下:
1、从后往前找两个相邻元素,前一个位置记为i,后一个记为j,并且满足s[i] < s[j]
2、从后往前找另一个位置k,若满足s[i] < s[k],则将s[i]与s[k]交换,并将j之后(包括j)的所有元素颠倒排序,即得“下一个”数列。
先试着自己按照这个算法思路去模拟一下算法过程,看能不能悟出这个算法为什么是对的?如果还是不明白这个算法为什么是对的,再继续往下看。
举个例子,6 2 5 4 3 1,观察一下,下一个数列是6 3 1 2 4 5,回忆一下观察的过程,你是先从后往前找的对不对?你在找什么?
其实你在从后往前找,比较相邻两个数字,如果前一个数字比后一个数字大或相等,就继续往前找,直到找到前一个数字比后一个数字小,我们将前一个数字的位置记为i,后一个数字的位置记为j,此时应该满足s[i]<s[j]。这个例子中i = 1,j = 2。
可以看出从j开始的数列都是非升序排列的,因为刚刚在找的过程中,前一个数字都是比下一个数字大或相等。
要知道,非升序排列的数列不可能有“下一个”数列,即非升序排列的数列是“最大的”。那么从j开始的数列必定不存在“下一个”数列;另外一点,我们需要考虑i之前(不包括i)的数列吗?比如例子中的6,不需要!因为从i开始的数列必定存在“下一个”数列,因为它不是非升序排列的,非升序排列的数列必定存在“下一个”数列。所以结论是,我们只考虑从从i开始的数列找“下一个”数列。
从j开始的数列不可能有“下一个”数列,那么“下一个”数列的i位置放的值不能是原数,而应该从后面的数找,找比原数大的,然后这个数要尽量小。那么如何找到这个最小的数呢?因为从j开始的数列是非升序,所以从后往前找,找到比原数大的就行了。这个位置,我们记为k,例子中这个最小的数是3,即k=4。
找到k之后,交换i,k位置的值(一定可以找到这样的k,因为j位置就满足了)。交换之后,从j开始的数列依然是非升序排列。这个很明显,就不多解释了。
因为从j开始的数列是非升序排列,逆序一下,得到非降序排列,非降序排列是“最小的”。所以交换之后,从j开始,逆序排序一下,即得到“下一个”排列。
下面自己实现的源代码(原理同STL中的next_permutation)
View
Code
ps.理解源代码之后就可以知道为什么降序排列的数组,用STL中的next_permutation之后变成升序排列
最后再补充一个不规范的递归版本,所谓不规范,就是排列的顺序与STL中的next_permutation不一样。
给定一个数列,如何得到它的全排列?
例如1 2 3,它的全排列是123,132,213,231,312,321。
全排列的关键在于,给定某一数列,能从该数列推出“下一个”数列。
那么如何找“下一个”数列呢?
找“下一个”数列的算法思路描述如下:
1、从后往前找两个相邻元素,前一个位置记为i,后一个记为j,并且满足s[i] < s[j]
2、从后往前找另一个位置k,若满足s[i] < s[k],则将s[i]与s[k]交换,并将j之后(包括j)的所有元素颠倒排序,即得“下一个”数列。
先试着自己按照这个算法思路去模拟一下算法过程,看能不能悟出这个算法为什么是对的?如果还是不明白这个算法为什么是对的,再继续往下看。
举个例子,6 2 5 4 3 1,观察一下,下一个数列是6 3 1 2 4 5,回忆一下观察的过程,你是先从后往前找的对不对?你在找什么?
其实你在从后往前找,比较相邻两个数字,如果前一个数字比后一个数字大或相等,就继续往前找,直到找到前一个数字比后一个数字小,我们将前一个数字的位置记为i,后一个数字的位置记为j,此时应该满足s[i]<s[j]。这个例子中i = 1,j = 2。
可以看出从j开始的数列都是非升序排列的,因为刚刚在找的过程中,前一个数字都是比下一个数字大或相等。
要知道,非升序排列的数列不可能有“下一个”数列,即非升序排列的数列是“最大的”。那么从j开始的数列必定不存在“下一个”数列;另外一点,我们需要考虑i之前(不包括i)的数列吗?比如例子中的6,不需要!因为从i开始的数列必定存在“下一个”数列,因为它不是非升序排列的,非升序排列的数列必定存在“下一个”数列。所以结论是,我们只考虑从从i开始的数列找“下一个”数列。
从j开始的数列不可能有“下一个”数列,那么“下一个”数列的i位置放的值不能是原数,而应该从后面的数找,找比原数大的,然后这个数要尽量小。那么如何找到这个最小的数呢?因为从j开始的数列是非升序,所以从后往前找,找到比原数大的就行了。这个位置,我们记为k,例子中这个最小的数是3,即k=4。
找到k之后,交换i,k位置的值(一定可以找到这样的k,因为j位置就满足了)。交换之后,从j开始的数列依然是非升序排列。这个很明显,就不多解释了。
因为从j开始的数列是非升序排列,逆序一下,得到非降序排列,非降序排列是“最小的”。所以交换之后,从j开始,逆序排序一下,即得到“下一个”排列。
下面自己实现的源代码(原理同STL中的next_permutation)
View
Code
ps.理解源代码之后就可以知道为什么降序排列的数组,用STL中的next_permutation之后变成升序排列
最后再补充一个不规范的递归版本,所谓不规范,就是排列的顺序与STL中的next_permutation不一样。
相关文章推荐
- MySQL主从复制(Master-Slave)与读写分离(MySQL-Proxy)实践
- 人脸识别,人脸关键点检测算法
- 一个杯子的测试用例
- alibaba/druid 使用ConfigFilter
- linux-mysql-rpm安装方式
- Swift学习之UILabel基本用法
- mysql超一亿条记录中快速查询总记录条数
- 2 million pixels RTMP protocol IP camera,Push stream to FMS/RED5/WOWZA
- UIResponder
- java怎么调用webservice
- 方法兼容
- 升级yosemite后java出错的解决
- boa,cgi 应用过程经验总结(404,502错误解决)
- 【python】编程语言入门经典100例--35
- Tomcat 7 + Java 8 : Invalid byte tag in constant pool: 15
- 【python】编程语言入门经典100例--34
- java集合源码分析
- Java IO流 学习笔记
- android支持多行的radiogroup
- Block的一些简单理解