[分析] 参考Code Ganker的思路:1)从低位往高位扫描数组,找到第一个小于其右边数字的位置 p;2)对p分两种情况讨论:a) 若 p >= 0, 即当前数组表示的数并非这个数组能表示的最大数,从p 右边下一个数开始往低位(向右)扫描数组,找到第一个不比p大的下标 q,则 q + 1处是p-q之间比 p 位置上的数字大的最小数,交换 p & q + 1,交换后 p 右边的是一个降序数列,逆序之几位 next permutation。 b) 若 p < 0, 则当前为所有排列中的最大值,逆序整个数组得到最小值。 如何理解这个思路的正确性?步骤1找到的p,其后面是一个降序数列,是后面那些数字排列能得到的最大值,也就是后面无论怎么排列都不可能使整个数组值更大,这说明是时候替换这段子序列前面那个领头数字了,从子序列中找一个比当前领头(p位置的数字)大的最小数字作为新领头,子序列再逆序下,这样得到的新排列是比之前排列对应数值大的最小排列。
实现时注意第一个while里头是 >=,因为我们要找到第一个破坏非降序性质的位置,第二个while里头是 >, 因为要通过找到第一个不比p大的数来找到大于 p 的最小数。
[ref]
http://blog.csdn.net/linhuanmars/article/details/20434115?utm_source=tuicool
public class Solution { public void nextPermutation(int[] nums) { if (nums == null || nums.length < 2) return; int p = nums.length - 2; while (p >= 0 && nums[p] >= nums[p + 1]) p--; if (p >= 0) { int q = p + 1; while (q < nums.length && nums[q] > nums[p]) q++; int tmp = nums[--q]; nums[q] = nums[p]; nums[p] = tmp; } reverse(nums, p + 1); } public void reverse(int[] nums, int i) { int j = nums.length - 1; while (i < j) { int tmp = nums[j]; nums[j] = nums[i]; nums[i] = tmp; i++; j--; } } }