題目描述
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
分析思路
首先,我們來看一個簡單的例子
比如158476531這個序列,我們如果只想它變大一點點,應該儘可能的不去增加高位。因爲增加高位會帶來更大的增益。所以對於一個長爲n的序列,我們增加第n位的前提是,前n-1位已經達到了最大排列方法。所以我們從後往前看:
1
31
531
6531
76531
上邊列舉的都是一個升序的序列,不可能變得更大了,先不動它。
然後,可以將4移到後面來來增大。但是問題在於,把誰移到4的位置。因爲是找下一個數,所以我們要找一個比4小卻儘可能大的數,所以找到5,交換變成576431。
把5換到4的位置後,後幾位(76431)仍然是個降序的排列,要做成一個以5開頭最小的序列,而這個序列應該是升序的,所以我們直接把76431倒置一下,就從降序變成升序了。
下面是一個找next permutation的動畫:
代碼
public void nextPermutation(int[] nums) {
if (nums.length <= 1) {
return;
}
int i = nums.length - 2;
// 找到第一個下降點,我們要把這個下降點的值增加一點點
//511特殊,要加=,下邊同理
while (i >= 0 && nums[i] >= nums[i + 1]) {
i--;
}
// 如果這個下降點還在數組內,我們找到一個比它稍微大一點的數替換
if (i >= 0) {
int j = nums.length - 1;
while (j > i && nums[j] <= nums[i]) {
j--;
}
swap(nums, i, j);
}
// 如果在之外,說明整個數組是降序的,是全局最大了
// 將下降點之前的部分倒序構成一個最小序列
reverse(nums, i + 1, nums.length - 1);
}
private void swap(int[] nums, int i, int j) {
int tmp = nums[j];
nums[j] = nums[i];
nums[i] = tmp;
}
private void reverse(int[] nums, int left, int right) {
while (left < right) {
swap(nums, left, right);
left++;
right--;
}
}