思路如下:
假设当前给定permutation序列为 a1 a2 a3...an.
- 从序列尾部a[n]开始向头部扫描,找到第一个相邻升序序列 a[i-1]< a[i] ; 因为是扫描到的第一个相邻升序,则此时有a[i]>=a[i+1]>=a[i+2]...>=a[n].
- 从a[n]逆序遍历至a[i] 找到第一个大于a[i-1]的值a[j] ,交换a[i-1]和a[j].因为a[j]是第一个大于a[i-1]的,所以有a[j+1]至a[n]都小于等于a[i-1]. 即替换后的序列a[1]...a[j],a[i],a[i+1]..a[j-1],a[i-1],a[j+1]...a[n] 有a[i]>=a[i+1]>=a[j-1]>=a[j]>a[i-1]>=a[j+1]...>=a[n].即从i-n的范围仍然是个非升序序列。
- 因为我们已经改变a[i-1]的值为其后序列中大于a[i-1]的值中最接近他的。那么剩下的只需将a[i]~a[n]的范围内的值变为升序序列即可。
示例: 3 2 6 5 4 1
我们找到第一个相邻升序序列 2 6 然后找到2的后面第一个大于2的值4 交换。变为 3 4 6 5 2 1
然后将6 5 2 1变为升序序列,得到最后结果 3 4 1 2 5 6
简单说明下正确性吧: 当找到第一个升序序列 2 6,由于是第一个升序序列,所以以6开头的6 5 4 1肯定是非升序的。对于一个非升序的permutation部分,肯定是这部分内最大的了,所以没办法操作他们去获得整个permutation的下一个值,则需要替换前一位2(用后面的大于他的最小值4替换,由于后面部分是递减的,大于他的最小值肯定是从尾往前第一个比他大的)。序列变为 3 4 6 5 2 1,因为4是第一个比他大的,所以1<2.又因为6>5>4>2.所以后面的序列6 5 2 1也是递减的,使用i,j指针 交换为递增的 1 2 5 6 即可。
代码
public void nextPermutation(int[] num) {
// Start typing your Java solution below
// DO NOT write main() function
if(num == null||num.length == 0) return ;
int i = num.length-1;
for(;i>=1;i--){
if(num[i]>num[i-1]){
break;
}
}
int j = num.length-1;
int temp;
if(i>=1){
i = i-1;
while(num[j]<=num[i]) j--;
temp = num[i];
num[i] = num[j];
num[j] = temp;
i = i+1;
}
j = num.length-1;
while(i<j){
temp = num[i];
num[i] = num[j];
num[j] = temp;
i++; j--;
}
}