#算法证明#证明字典序全排列生成算法及实现

缘起

在网上看到了字典序全排列生成算法,不懂为什么会这样可以算法可以生成当前序列的下一个字典序,于是便在思考能不能证明一下。

step1:
对于排列 a[0...n1]  ,找到所有满足 a[k]<a[k+1](1<k<n2)  的k的最大值,如果这样的k不存在,则说明当前排列已经是a的所有排列中字典序最大者,所有排列输出完毕。
step2:
a[k+1...n]  中,寻找满足这样条件的元素l,使得在所有 a[l]>a[k]  的元素中,a[l]取得最小值。也就是说 a[l]>a[k]  ,但是小于所有其他大于a[k]的元素。
step3:
交换 a[l]  a[k]  .
step4:
对于 a[k+1...n]  ,反转该区间内元素的顺序。也就是说a[k+1]与a[n]交换,a[k+2]与a[n-1]交换,……,这样就得到了a[1…n]在字典序中的下一个排列。

预备知识

首先要了解什么是字典序:

设想一本英语字典里的单词,何者在前何者在后?
显然的做法是先按照第一个字母、以 a、b、c……z 的顺序排列;如果第一个字母一样,那么比较第二个、第三个乃至后面的字母。如果比到最后两个单词不一样长(比如,sigh 和 sight),那么把短者排在前。(维基百科)

如果你不满足于上面的简单理解,可以看在wikipedia的严格定义

开始证明

首先对于一个字符串,每一个字符可能为c1、c2、c3……cm的m个有序字符中的一个。我们定义:

abab, 

例如c3 - c1 = 第3个 - 第1个= 2.
假设我们现在又有两个长度为n的字符串A、B,其中A、B的每个字符有m种可能。定义:
ABd(A,B)= i=0 n1 (A i B i )m n1i  

显然,我们要证明字典序全排列生成算法有效,即此算法能生成的A的下一个字典序全排列,则需证明
d(A next ,A)>0d(A next ,A)=min{d(AA)}A next A() 

证明step1
要使(*)成立,则A的某一位 A k   则必须被替换为 A j ,  其中 A j >A k j>k  这样生成的 A next   才会使 d(A next ,A)>0  .
又因为 d(A next ,A)  尽量小,所以 A k   必须是序列A中满足 A i <A i+1   的下标最大(即最右边)的一个。这用反证法根据 d(A,B)  的定义可以证明。如找不到这样的 A i   说明A已经没有下一个更大的字典序全排列了。
证明step2和step3
step1后, A next 0  A next 1  A next k1    都确定了,即 A 0 A 1 A k1   ,否则 d(A next ,A)  将变大。我们此时能动的是 A k A k+1 A n1  
已知 A k   要被调换,为了使 d(A next ,A)  尽量小, A k   应该被调换为 A k+1 A n1   中最小的一个。这用反证法根据 d(A,B)  的定义可以证明。
证明step4
step2和step3后, A next k    位置也被固定。还能动的是 A k+1 A n1  

我们注意到,在step1中:因为 A k   必须是序列A中满足 A i <A i+1   的下标最大(即最右边)的一个, A k+1 A n2   都不符合这个性质,所以序列 A k+1 A n1   是非递增的
显然,经过step2和step3后的 A k+1 A n1   仍然是非递增的。
由于step2,step3已经保证 d(A next ,A)>0  ,我们只需要重排 A i+1 A n1   来使 d(A next ,A)  尽量小,即

 i=k+1 n1 (A next i  A i )m n1i  
尽量小。
上面说了:序列 A k+1 A n1   是非递增的,所以我们只要将序列 A k+1 A n1   逆转,便可以使上式最小。这样子权重越大,系数越小,从而保证上式最小。
这样
A next k+1  A next k+2  A next n1    也确定了,它们是 A n1 A n2 A k+1  

结论

最终 A next   的每一个字符都被确定下来,并且(*)成立,这说明上述算法确实是有效的。

思考

证明的时候进一步发现这个算法的思路是,在保证(*)成立的前提下,逐渐确定 A next   的每一个字符,最终确定了 A next   的所有字符,所得出得字典序全排列便是我们想要的。
这是局部最优达到全局最优的一个典型例子。

实现

具体实现在我的另一篇博客中。

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值