1. 程式人生 > 實用技巧 >Leetcode31.下一個排列

Leetcode31.下一個排列

題目:下一個排列

思路:找規律。在字典序中,用在字典中出現的次序代表該字元的值,用直接連線字元,那麼最小排列的字串就是單調遞增的一條直線。從最小排列開始逐漸增大排列,那麼可以發現從直線的末端開始,會不斷的出現頂點並向前延伸,直到直線變成了單調遞減。可以發現每一次增大的排列都是末端頂點向前移動。為了更好的說明情況,這邊引用題解中的一張圖。

圖中可以知道,當前的排列是```12385764```。可以看到圖中有兩個頂點,分別為8和7,那麼可以改變末端頂點附近的字元獲得下一個排列。步驟如下:
  • 從尾端向前搜尋,直到到達第一個頂點處;(從4向1方向搜尋,7這個位置)
  • 那麼頂點的前一個字元,就是我們需要被替換的字元,替換的字元是在剛剛搜尋中比被替換字元大一點的字元;(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;
        }
    }
}