字典序算法
我们都知道字典中的单词是如何排列的,即首先比较第一个,如果哪一个较小那么这个单词就排在前面,如果相等,那么比较第二个,依此类推。在c++的STL中也有一个类似的算法,即next_permutation
,它按照字典一样的排序算法,计算出一个序列的下一个序列是什么,例如32456983
的下一个就是32458369
,下面来详细说明一下原理,步骤和解释。
原理:
我们要找下一个序列,就是找到比当前序列所有大的序列中最小的一个,毫无疑问,我们就要尽量向后找可以变大的元素,如果存在ai < aj (i < j),那么一定能找到下一个序列,那么如何确定这个需要开始起变化的元素呢?就是要找到最后一个这样的ai,这样才能得到最小的一个。找到之后该如何操作呢?我们在后面找到最小的比ai大的元素和ai交换,然后在位置i后面的元素从小到大排列,这个新的的序列就是按字典序的下一个序列。
步骤:
- 找到最后一个元素,这个元素满足在它的后面存在比它大的元素的条件,记为ai。
- 然后找到ai后面最后一个比ai大的元素aj。
- 接着,交换ai和aj的值,然后将ai和aj之间的部分翻转。
解释:
第一步已经在原理中说明了。第二步为什么要找最后一个比ai大的元素呢?其实这句话就是指的比ai大的元素中最小的一个,因为第一个步骤保证了aj前面不会有比它小的元素,不然ai也不会称为第一步确定的元素,所以最后一个就是最小的一个,二不说最小的一个是为了代码实现更易懂。而aj之后的元素是比ai小的,所以ai和aj交换位置以后,在位置i后面的元素是从小到大排列的,然后进行第三部倒转,就能得到下一个序列。
代码例子:
bool my_next_permutation(char* p, int num){
int i;
for (i = num - 2; i >= 0; --i) {
if (p[i] < p[i + 1])
break;
}
if (i == 0)
return false;
int j = i + 1;
while (p[j] > p[i])
++j;
swap(p[i], p[j - 1]);
reverse(p + i + 1, p + num);
return true;
}