Leetcode31.下一个排列

题目:下一个排列

思路:找规律。在字典序中,用在字典中出现的次序代表该字符的值,用直接连接字符,那么最小排列的字符串就是单调递增的一条直线。从最小排列开始逐渐增大排列,那么可以发现从直线的末端开始,会不断的出现顶点并向前延伸,直到直线变成了单调递减。可以发现每一次增大的排列都是末端顶点向前移动。为了更好的说明情况,这边引用题解中的一张图。

图中可以知道,当前的排列是12385764。可以看到图中有两个顶点,分别为8和7,那么可以改变末端顶点附近的字符获得下一个排列。步骤如下:
  • 从尾端向前搜索,直到到达第一个顶点处;(从4向1方向搜索,7这个位置为搜索到的第一个顶点)
  • 那么顶点的前一个字符,就是我们需要被替换的字符,替换的字符是在刚刚搜索中比被替换字符大一点的字符;(5是被替换的字符,7和6都比5大,选其中最小的作为替换字符,这儿选6是替换字符)
  • 替换完后对从顶点位置开始进行升序排列。(替换后的排列是12386754,从顶点7开始排序,即754->457
  • 上述步骤完成后,就得到下一个排列。(12385764->12386457

代码:

class Solution {
     public void nextPermutation(int[] nums) {
        int idx = nums.length-1;
        while(idx > 0 && nums[idx] <= nums[idx-1]) --idx;
        if(idx <= 0) {
            reverse(nums);
        }else{
            int i = idx;
            while(i<nums.length && nums[i] > nums[idx-1]) i++;
            int t = nums[idx-1] ^ nums[i-1];
            nums[idx-1] ^= t;
            nums[i-1] ^= t;
            Arrays.sort(nums, idx, nums.length);
        }
    }
    private void reverse(int[] nums){
        for(int l = 0, r = nums.length - 1, t = 0; l < r; l++, r--){
            t = nums[l] ^ nums[r];
            nums[l] ^= t;
            nums[r] ^= t;
        }
    }
}

执行用时:1 ms, 在所有 Java 提交中击败了96.93%的用户
内存消耗:38.5 MB, 在所有 Java 提交中击败了79.92%的用户

原文地址:https://www.cnblogs.com/liuyongyu/p/14201094.html