(一)題目描述
實現獲取下一個排列的函數,算法需要將給定數字序列重新排列成字典序中下一個更大的排列。
如果不存在下一個更大的排列,則將數字重新排列成最小的排列(即升序排列)。
必須原地修改,只允許使用額外常數空間。
以下是一些例子,輸入位於左側列,其相應輸出位於右側列。 1,2,3 → 1,3,2 3,2,1 → 1,2,3 1,1,5 → 1,5,1
(二)算法思路
首先解釋一下什么是字典序:
設P是1~n的一個全排列:p=p1p2......pn=p1p2......pj-1pjpj+1......pk-1pkpk+1......pn
1)從排列的右端開始,找出第一個比右邊數字小的數字的序號j(j從左端開始計算),即 j=max{i|pi<pi+1}
2)在pj的右邊的數字中,找出所有比pj大的數中最小的數字pk,即 k=max{i|pi>pj}(右邊的數從右至左是遞增的,因此k是所有大於pj的數字中序號最大者)
3)對換pj,pk
4)再將pj+1......pk-1pkpk+1......pn倒轉得到排列p'=p1p2.....pj-1pjpn.....pk+1pkpk-1.....pj+1,這就是排列p的下一個排列。
解法:
解法一:我們可以把所有的排序全部列出來,然后找到下一排列,但是這樣的算法效率太低,LeetCode肯定不能通過.但是這也是最簡單和最容易想到的方法了.
解法二:一遍掃描法
- 我們直接從后往前掃描,先把最后一位當做基准,
- 看倒數第二位比倒數第一位大還是小,如果比倒數第一位大,呢就把倒數二位當做基准,直到找到比它小的一位數,我們將其記為 a.
- 然后用這位數去和它之后的數進行比較,找到比它大的數中最小的一位b.
- 然后交換a和b的位置
- 再將a之后的數字逆序排列,就是最終的結果.
我覺得自己已經解釋的很清楚了,但是為了大家更好的去理解這個過程,下面請看一張動圖,就能更加清晰的掌握這個過程了.(圖是借鑒領扣的)

(三)LeetCode AC代碼
1 public class Solution { 2 public void nextPermutation(int[] nums) { 3 int i = nums.length - 2; 4 while (i >= 0 && nums[i + 1] <= nums[i]) { 5 i--; 6 } 7 if (i >= 0) { 8 int j = nums.length - 1; 9 while (j >= 0 && nums[j] <= nums[i]) { 10 j--; 11 } 12 swap(nums, i, j); 13 } 14 reverse(nums, i + 1); 15 } 16 17 private void reverse(int[] nums, int start) { 18 int i = start, j = nums.length - 1; 19 while (i < j) { 20 swap(nums, i, j); 21 i++; 22 j--; 23 } 24 } 25 26 private void swap(int[] nums, int i, int j) { 27 int temp = nums[i]; 28 nums[i] = nums[j]; 29 nums[j] = temp; 30 } 31 }
雖然不是很難,但是自己還是搞了很久.
自己將其總結下來,相信慢慢的自己會有思路去寫算法.
