lintcode52:下一个排列

描述

给定一个整数数组来表示排列,找出其之后的一个排列。

排列中可能包含重复的整数

样例

给出排列[1,3,2,3],其下一个排列是[1,3,3,2]

给出排列[4,3,2,1],其下一个排列是[1,2,3,4]

思路:

1. 先找到需要改变的高位:从右向左扫描排列,若一直满足nums[i] > nums[i - 1],则说明这些元素是满足高位大于低位的,不需操作,直到找到nums[i] < nums[i - 1],找到高位比低位小的了,而且是“最低”的高位,这个位置就是我们需要做交换操作的。比如:6, 8, 7, 4, 3, 2 当中的8(发现6 < 8)

2. 第二步找要和这个高位交换的低位:原则是尽量寻找只比这个高位“大一点”的低位,因为只是下一个排列。因为在这个高位右边的数组满足从右往左递增,所以,我们重新从右边起扫描,找到第一个比这个高位大的元素。比如:6, 8, 7, 4, 3, 2 中的7.

3. 交换高位与低位,使得高位变大:比如6, 8, 7, 4, 3, 2 -> 7, 8, 6, 4, 3, 2

4. 此时,不论交换后的高位后面的元素是如何排列的,都肯定比之前的排列靠后了。因为只是下一个排列,所以我们现在尽量要现在的这个排列“靠前”,怎么做呢,就是按升序排列高位后面的元素,比如:按升序排列此时7后面的元素。因为此时高位后面的元素一定是从左往右,从大到小,所以,也相当于是翻转这一部分的数组。比如:78, 6, 4, 3, 2 -> 72, 3, 4, 6, 8

Java代码:

public static int[] nextPermutation(int[] nums) {
        // write your code here
        if(nums==null || nums.length==0 || nums.length==1){
            return nums;
        }
        // 从右边开始找前一位比当前位小的数
        int len = nums.length;
        int i = len-1;
        for (;i>0;i--){
            if(i>0 && nums[i]>nums[i-1]){
                break;
            }
        }
        // 因为需要找下一个大的数,所以从右向左,找到第一个刚刚比 i-1 位置大的那个数
        if(i>0){
            int j = len-1;
            for (; j > i-1; j--) {
                if(nums[j]>nums[i-1]){
                    break;
                }
            }
            // 交换 i-1 j
            int temp = nums[i-1];
            nums[i-1] = nums[j];
            nums[j] = temp;
        }

        // 逆转 i-1 后面的数组
        int pre = i, last = len-1;
        while (pre<last){
            int temp = nums[pre];
            nums[pre] = nums[last];
            nums[last] = temp;
            pre++;
            last--;
        }
        return nums;
    }
参考: https://blog.csdn.net/guoziqing506/article/details/51787763

猜你喜欢

转载自blog.csdn.net/u012156116/article/details/80704719