Next Permutation-leetcode下一个排列组合

问题描述:
Implement next permutation, which rearranges numbers into the lexicographically next greater permutation
of numbers.
If such arrangement is not possible, it must rearrange it as the lowest possible order (ie, sorted in ascending
order).
The replacement must be in-place, do not allocate extra memory.
Here are some examples. Inputs are in the left-hand column and its corresponding outputs are in the
right-hand column.
1,2,3 → 1,3,2
3,2,1 → 1,2,3
1,1,5 → 1,5,1

STL源码剖析>>page:380对此问题有详尽描述,相当于实现算法里面的next_permutation()函数,与之对应的另一个函数是prev_permutation()

这里在自己撸一下思路:

什么是下一个全排数列,如abc的下一个是acb,就是按照字典的搜索顺序排列

以数组{1,2,4,6,5,3}为例

下一个排列和当前排列应该具有尽可能长的公共前缀,所以从数组后面后向推算

从3开始找,{3}只有一个数,所以无下一个全排

继续看{5,3}无下一个全排

{6,5,3}无下一个全排

也就是说,如果序列是有序并且是降序时无下一个全排

那我们从后向前找到降序数列和无序数列的分界线,即4和6那儿即可

怎么找?从后向前,比较相邻的元素,直到找到前小后大的

注:如果一直遍历到1的位置都没有找到,说明此序列为全递减的(按照题意,将其逆序即可)

此时,1,2已经是两个序列的公共前缀,也就是说,我们只要找到{4,6,5,3}的下一个排列即可

怎么找?4653是这四个数字组合中4开头的数字中最大的那个,我们需要从653中找到刚好比4大的数字,即5,

让5和4交换数列变成了5643,那只要找到以5开头的数的最小排列即可

怎么找?可以发现5后边的643是降序的,那只要让643为346逆序即可

{1,2,4,6,5,3}的下一个排列为{1,2,5,3,4,6}

再将上面的思路具体化一下:

  • 让两个指针pi和pi_front分别指向数列的倒数第一个和倒数第二个

  • 从后向前遍历两两比较,找到前小后大的一对,此时pi指向大的(6),pi_front指向小的(4)

  • 用 j 重新从后向前遍历,直到找到比pi_front大的数,交换 j 和pi_f的值

  • 把pi_f后面的所有数全部反转

  • 进行判断,如果整个序列为降序,那么反转所有的元素

代码如下:

bool NextPermutation(int *start,int *end)//[start,end)
{
    assert(start != NULL && end != NULL);
    int* pi = start;
    if(pi == end || ++pi == end)//只有一个元素时
        return false;
    pi = end;
    --pi;
    int* pi_front = --pi;
    ++pi;
    while(*pi < *pi_front)
    {
        --pi;
        --pi_front;
    }
    int* j = end;
    while(*--j < *pi_front);

    iter_swap(pi_front,j);
    reverse(pi,end);
    return true;
    if(pi_front == start)//全递增数列,全部逆序
    {
        reverse(start,end);
        return false;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值