Next_permutation原理、全排列转换最小代价、优化“swap相邻元素”过程

下一个排列

 其实,我们完全没有必要去背诵: next_permutation在干嘛
 我们需要知道,什么叫做:  “下一个排列”
 s = "123"   他的所有全排列ALL: 123, 132, 213, 231, 321, 312
 所谓“下一个排列”:   即给定某个排列(比如“213”),求他在ALL里的下一个排列(即231)
 		即,下一个排列  他从某种10进制数字的角度去看,也就是数值增大的过程
 ' 全排列ALL的个数,不一定等于n!   如果没有重复元素,确实是n! '
 '   但如果有重复数字, 比如(122333) 那他的全排列有:6! / 2! / 3! 个 '

我们需要2个问题: 
	1, next_permutation是怎么实现的
	2, 他是时间复杂度

next_permutation实现原理

cur = 	xxxx 4 6 5 5 4 4 3 2
	         i     j
他的下一个排列nex是:  xxxx 5 2 3 4 4 4 5 6
1, 从后往前找,找“第一个”满足: A[i] < A[i + 1]的点,即图中[i]的位置
    (nex[i]一定放的是>4的数!! 因为,i后面 已经是递减达到饱和了 )
2, “再次”从后往前找, 第一个 > A[i]=4 的位置 即[j]
	swap(A[i], A[j])
3, 此时变成: xxxx 5 6 5 4 4 4 3 2
				   i
	然后执行: reverse( A.begin() + i + 1, A.end() );
最后的nex = xxxx 5 2 3 4 4 4 5 6

bool Next_permutation(vector<int>& A){
   
     int n = A.size();
     for(int i = n - 2; i >= 0; --i){
   
         if(A[i] < A[i + 1]){
    ' 一旦这个if成立, 下面的 return true一定会执行!!'
         ' 意味着:  这个算法的时间是: O(n)的!!! '
             for(int j = n - 1; ; --j){
   
                 if(A[j] > A[i]){
    ' 一定会找到 '
                     swap(A[i], A[j]);
                     reverse(A.begin() + i + 1, A.end());
                     return true;
                 }
             }
         }
     }
     return false; ' 说明,A已经达到饱和,比如: 4 4 3 3 2 2 '
 }

' 他的时间为:   [8 9 8 8 8 ... ]  '
'   n + n + (reverse=n) = 3n, 即O(n)的时间!!! '
'   这个时间的分析, 非常非常容易出错!!! '
'   因为有2层的O(n)的循环,你很容易会认为: 是O(n^2)的时间 !! '
'   对时间分析的出错, 会导致 非常严重的后果!!! '
'因为我们: 第一次for循环,是有个一个if判断的!!  '
'一旦if成立,第二次的for循环里的if 也必然会成立!! 导致,时间其实是O(n+n)的!!'

next_permutation时间分析

假如从[1,2,3...,n]无限执行下一个排列, 那么 此时的时间,肯定是和他的全排列个数是相关的
 他有n!的排列, 那么时间 至少是n!量级的,这还不算我们的next算法的时间
 这个时间比较复杂, 平时也基本不会用到
 
但,假如给定你一个K,让你求cur的下K个排列 是什么?  (保证,下K个排列一定存在,不会溢出)
  ' 这个问题,你肯定会思考一会....  但其实,没有什么简易的方法,就是暴力 '
  即: while(k --){
     Next_permutation(A); } 
  关键是,我们要分析时间!! 
  K * (n) = k*n    ' 千万千万不要把next_permutation,分析成n^2的时间!! '

两个全排列间的转换

问题:  给定两个全排列(即各个数字出现的次数相同)比如beg=[1<
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值