当前位置: 代码迷 >> 综合 >> 【STL】next_permutation 算法原理
  详细解决方案

【STL】next_permutation 算法原理

热度:89   发布时间:2024-02-22 08:07:23.0

参考:

  • 【博客园】 STL next_permutation 算法原理和自行实现
  • 【CSDN】next_permutation和pre_permutation源码解析

基本思路

【STL】 next_permutation 函数就是返回当前序列的下一个字典序,已经为最大字典序则返回 False,否则为返回 True

基本思想如下:

  1. 从尾端开始依次比较两个相邻元素直到存在 ai,ai+1a_i,a_{i+1}ai?,ai+1? 满足 ai<ai+1a_i < a_{i+1}ai?<ai+1?,如果未找到返回 False
  2. 从尾端开始向前检验,找出第一个大于 aia_iai? 的元素 aja_jaj?,交换 ai,aja_i,a_jai?,aj?
  3. aia_iai? 之后(不包括 aia_iai?)的序列做反序处理

可能的代码实现:

template<class BidirIt>
bool next_permutation(BidirIt first, BidirIt last)
{
    if (first == last) return false;BidirIt i = last;if (first == --i) return false;while (true) {
    BidirIt i1, i2;i1 = i;if (*--i < *i1) {
    i2 = last;while (!(*i < *--i2));std::iter_swap(i, i2);std::reverse(i1, last);return true;}if (i == first) {
    std::reverse(first, last);return false;}}
}

简单证明

上面给出了思路,这里做一个简单证明

对一个序列 a0,a1,?,ai,ai+1,?,an?1a_0,a_1,\cdots,a_i,a_{i+1},\cdots,a_{n-1}a0?,a1?,?,ai?,ai+1?,?,an?1?,必定存在 iii,使得 a0?aia_0 \sim a_ia0??ai?,为正序,ai+1?an?1a_{i+1}\sim a_{n-1}ai+1??an?1? 为逆序(这里正序指的是从小到大的顺序,逆序为从大到小),这里对应了上面的步骤 1

现在需要求此序列的下一个字典序,容易得到,ai+1?an?1a_{i+1}\sim a_{n-1}ai+1??an?1? 已经为逆序(也为递减数列),不存在更大的字典序,但 ai?an?1a_{i}\sim a_{n-1}ai??an?1?,并不是逆序,即存在更大的字典序

显然以 aia_iai? 作为 ai?an?1a_{i}\sim a_{n-1}ai??an?1? 的首元素已经达到最大,所以需要在 ai+1?an?1a_{i+1}\sim a_{n-1}ai+1??an?1? 中找到一个元素替换 aia_iai?,显然此元素为大于 aia_iai? 的最小元素,因为数列 ai+1?an?1a_{i+1}\sim a_{n-1}ai+1??an?1? 为递减数列,所以只需要从末端开始向前寻找第一个大于 aia_iai? 的元素即可,记此元素为 aja_jaj?,即步骤 2

因为 aj>aia_j > a_iaj?>ai?,所以 aja_jaj? 作为首元素的最小排列为 ai+1?an?1a_{i+1} \sim a_{n-1}ai+1??an?1? 的顺序表示即可。交换后的序列仍然为逆序的,所以只需要反序处理即可,对应步骤 3