LeetCode | Next Permutation(下一个排列)


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

寻找下一个由这几个数字组成的数据比原数据大。相当于让n个数字组成的数据,由小到大排列,指定一个序列,查找在排列中的下一个序列。如果指定的是排列中的最后一个序列,则返回第一个序列。

比如,{3,2,5,8,7,6,6,5,5,4,2};我们要返回:326245556678。将6和5换位置,然后将后面的数据从小到大输出。如果只思考到这里的话,题目还是很复杂,写的代码量也很大。我们在深入一些考虑,从后往前遍历的过程中,找到第一个arr[i] < arr[i+1]得出要交换arr[i]和某一个数据,但通过例子来看,不能简单的将i+1和i交换。因为后续还可能有介于二者之间的数据。那我们就要找从后向前遍历的过程中第一个比arr[i]大的数据。

如果考虑二分查找,不考虑出现和arr[i]相等的数据的话,可以这样实现:

int Search(int *buf,int left,int right,int key)
{
    int mid;

    while(left <= right){
        mid = (right + left)/2;
        if(buf[mid] > key)
            left = mid+1;
        else
            right = mid-1;
    }

    return right;
}

注意:序列是从后向前递增的。返回的是第一个大于arr[i]的位置。

但是如果从n-1 –> i+1的过程中有和arr[i]相等的数据,那么这个程序返回的是第一个等于arr[i]的位置。将会产生错误。这时程序中需要分情况,有无和arr[i]相等的数据,分成两个不同的遍历模式。

下面的是以笨方法实现的,从后向前遍历,找到第一个大于arr[i]的位置,交换。


上面才是第一步,交换后呢?还需要利用快排、堆排序、归并排序等进行排序么?不用!我们要分析剩余数组的结构,从后向前是递增的,我们要做的就是反序。那么两两交换就可以了,不用排序。

分析到这里这道题目就算分析清楚了,上代码:

#include <stdio.h>
#include <stdlib.h>

void swap(int *a,int *b);
void NextPermutation(int *buf,int n);
void Print(int *buf,int n);

int main(void)
{
   // int buf[11] = {3,2,5,8,7,6,6,5,5,4,2};
    int buf[8] = {8,7,6,6,5,5,4,2};
    int n = 8;

    NextPermutation(buf,n);
    Print(buf,n);


    return 0;
}

void Print(int *buf,int n)
{
    for(int i = 0;i < n;++i){
        printf("%d ",buf[i]);
    }
    printf("\n");
}


void NextPermutation(int *buf,int n)
{
    int i = n-2;

    for(;i >= 0;--i){
        if(buf[i] < buf[i+1]){
            int j = i+2;
            while(j < n){
                if(buf[j] <= buf[i])
                    break;
                ++j;
            }
            --j;
            swap(&buf[i],&buf[j]);
            int lo = i+1,hi = n-1;
            while(lo<hi){
                swap(&buf[lo],&buf[hi]);
                lo++;
                hi--;
            }
            break;
        }
    }
    if(i<0){
        int lo = 0,hi = n-1;
        while(lo<hi){
            swap(&buf[lo],&buf[hi]);
            lo++;
            hi--;
        }
    }
}

void swap(int *a,int *b)
{
    int temp;
    temp = *a;
    *a = *b;
    *b = temp;
}


推荐链接:next_permutation的原理和使用


点赞