Next Permutation

本文介绍如何通过算法找出全排列中某一个排列的下一个排列,并提供多种编程语言实现方式,包括C++和Java。针对不同情况(如元素是否重复),讨论了算法的时间复杂度,并给出优化方案。

题目

求全排列中某一个排列的下一个排列

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

思路

对于没有元素重复的情况:

(1)从右往左,找到第一个可以逆序的逆序对,例如 2 1 4 3 第一个逆序对是 1<3 ,  2 4 3 1 第一个逆序对是 1<2 ;

(2)若找到的逆序对下标是 num[ i ]<num[ j ] ,交换两者的值;

(3)翻转 num 中 i+1~end 的数据,即为结果。

class Solution {
public:
    void nextPermutation(vector<int> &num) {
        // Start typing your C/C++ solution below
        // DO NOT write int main() function
        int i=num.size()-1;
        int j=num.size()-1;
        bool flag = false;  //if have the reverse-pair;
        for(i=num.size()-1;i>0;i--)
        {
            for(j=i-1;j>=0;j--)
                if(num[j]<num[i])
                {
                    flag = true;
                    break;
                }
            if(flag)
                break;
        }
        if(j>=0)
        {
            int tmp = num[i];
            num[i] = num[j];
            num[j] = tmp;
        }
        reverse(num.begin()+j+1,num.end());
    }
};

 

上述代码小数据可以通过。再简化一下:

class Solution {
public:
    void nextPermutation(vector<int> &num) {
        // Start typing your C/C++ solution below
        // DO NOT write int main() function
        for(int i=num.size()-1;i>0;i--)
        {
            for(int j=i-1;j>=0;j--)
                if(num[j]<num[i])
                {
                    int tmp = num[i];
                    num[i] = num[j];
                    num[j] = tmp;
                    reverse(num.begin()+j+1,num.end());   
                    return ; 
                }
        }
        reverse(num.begin(),num.end());
        return ;
    }    
};

 

如果存在重复的情况,上述代码存在一个问题:

例如 对于一个 数列 4 1 2 3 2 ,正确的逆序对是 2<3 ,而上述找到的是1<2 ,所以找到的不是一个理想的逆序对。

时间复杂度是O(N2),更正之后的代码:

class Solution {
public:
    void nextPermutation(vector<int> &num) {
        // Start typing your C/C++ solution below
        // DO NOT write int main() function
        for(int i=num.size()-2;i>=0;i--)
        {
            for(int j=num.size()-1;j>i;j--)
                if(num[i]<num[j])
                {
                    int tmp = num[i];
                    num[i] = num[j];
                    num[j] = tmp;
                    reverse(num.begin()+i+1,num.end());   
                    return ; 
                }
        }
        reverse(num.begin(),num.end());
        return ;
    }    
};

 

当然上述还可以进一步简化至时间复杂度 O(N)

class Solution {
public:
    void nextPermutation(vector<int> &num) {
        // Start typing your C/C++ solution below
        // DO NOT write int main() function

        int i=0;
        for(i=num.size()-2;i>=0;i--)
        {
            if(num[i]<num[i+1])
                break ;
        }
        for(int j=num.size()-1;j>i;j--)
        {
            if(num[i]<num[j])
            {
                int tmp = num[i];
                num[i] = num[j];
                num[j] = tmp;
                reverse(num.begin()+i+1,num.end());   
                return ; 
            }
        }
        reverse(num.begin(),num.end());
        return ;
    }    
};


最新 java

public class Solution {
    public void nextPermutation(int[] num) {

        //1.找到最后一个升序位置pos  
        int pos = -1;  
        for (int i = num.length - 1; i > 0; i--) {  
            if (num[i] > num[i - 1]) {  
                pos = i - 1;  
                break;  
            }  
        }  
          
        //2.如果不存在升序,即这个数是最大的,那么反排这个数组  
        if (pos < 0) {  
            reverse(num, 0, num.length - 1);  
            return;  
        }  
          
        //3.存在升序,那么找到pos之后最后一个比它大的位置  
        for (int i = num.length - 1; i > pos; i--) {  
            if (num[i] > num[pos]) {  
                int tmp = num[i];  
                num[i] = num[pos];  
                num[pos] = tmp;  
                break;  
            }  
        }  
          
        //4.反排pos之后的数  
        reverse(num, pos + 1, num.length - 1);  
    }  
      
    public void reverse(int[] num, int begin, int end) {  
        int l = begin, r = end;  
        while (l < r) {  
            int tmp = num[l];  
            num[l] = num[r];  
            num[r] = tmp;  
            l++;  
            r--;  
        }  
    } 
    
}


 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值