31. 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

分析

题目要求是给出一个数字排列中按字典序排列的下一个更大的排列。如果没有更大的则给出最小的,比如1,2,3->1,3,2下一个字典序更大的排列是1,3,2,而3,2,1是最大的字典序排列,修改为最小的1,2,3。
解这道题可以通过观察,1,4,3,2 -> 2,1,3,4分为三步:

  1. 逆向寻找到第一个非递减的数nums[i] < nums[i+1]
  2. 将这个数与后面最后一个比它大的数调换(仅大于它),不能找最后一个,因为最后一个不一定大于它。
  3. 将这个数后面重新排序,让后面的数最小

这样看第一步找到1,第二步将1与2调换得到2,4,3,1,第三步将2后面的4,3,1排序,得到2,1,4,3
需要注意的是,如果这个序列全部递减(最大),则直接重新排序即得到最小序列
这个方法的原始出处在这里

复杂度分析

最多对数组进行了3次扫描,时间复杂度为O(n),空间复杂度为O(1)

代码

public void nextPermutation(int[] nums) {
    if(nums == null || nums.length <= 1) return;

    int i = nums.length - 2;
    for(; i >= 0 && nums[i] >= nums[i+1]; --i); //第一步
    if(i >= 0){  //否则全部都是递减的,不需要调换了
        int j = i+1;
        for(; j < nums.length && nums[j] > nums[i]; ++j);  //这里是大于,不能加等于
        swap(nums, i, j - 1);  //第二步
    }

    int j = nums.length - 1;  //因为后面肯定是逆序的,所以直接两点调换即可
    for(i = i + 1; i < j; i++,j--){
        swap(nums, i, j);
    }
}

public void swap(int[] nums, int index1, int index2){
    int i = nums[index1];
    nums[index1] = nums[index2];
    nums[index2] = i;
}

你可能感兴趣的:(31. Next Permutation)