LeetCode 31--下一个排列 ( Next Permutation )

题目描述: :

根据题目所给条件 : 

输入 : 1 , 2 , 3    →   1 , 3 , 2

          1 , 3 , 2     →   2 , 1 , 3

          2 , 1 , 3     →   2 , 3 , 1

          2 , 3 , 1     →   3 , 1 , 2

          3 , 1 , 2     →   3 , 2 , 1

我们可以发现 , 当输入排列不是从大到小序列是 , 每个输出序列都是比输入序列大的最小值 , 所以每次只需要确定输入序列的下一次序列即可 : 

假如 : 输入为  : 4  5  7  6  3  2  1  0

时间复杂度O(n^2) 空间复杂度O(1)

首先 , 从后往前遍历寻找比当前小的数值 , 即找到5的位置停止 , 然后再从后往前遍历寻找比5大的数值 ,找到6停止 , 再将5和6进行交换 , 序列变为 4  6  7  5  3  2  1  0  , 再把6之后的元素逆置 , 4  6  0  1  2  3  6  7 , 这样就得到输入序列的下一个更大的序列

时间复杂度O(n) 空间复杂度O(1)

可以先寻找上一个比当前小的数值 , 找到后交换并跳出循环 , 然后再将后边的数组逆序 , 如果没找到就直接将整个数组逆序 ,

时间复杂度为 O(2n)

代码如下 : 

//取址交换函数
void swap(int *a,int *b )
{
    int cur=*a;
    *a=*b;
    *b=cur;
}
void nextPermutation(int* nums, int n) {
    if(n<=1)
        return;
    if(n==2){
        swap(&nums[0],&nums[1]);
        return;
    }
    for(int i=n-1;i>0;i--){
        //寻找上一个比当前数小的值
        if(nums[i-1]<nums[i]){
            //从后往i-1寻找比i-1下标代表元素小的元素
            for(int j=n-1;j>=i;j--){
                //找到后将两者交换
                if(nums[j]>nums[i-1]){
                    swap(&nums[j],&nums[i-1]);
                    break;
                }
            }
            //再将从i到数组末尾进行两两交换
            //注意循环边界
            for(int j=0;j<(n-i)/2;j++){
                swap(&nums[i+j],&nums[n-j-1]);
            }
            return;
        }
    }
    //如果没有返回,证明该数组已经是最大的排序,只需要将数组逆置交换即可
    //注意循环边界
    for(int i=0;i<n/2;i++){
        swap(&nums[i],&nums[n-i-1]);
    }
    return;
}

猜你喜欢

转载自blog.csdn.net/ds19980228/article/details/82694255