1 题目
给出一个正整数,找出这个正整数所有数字全排列的下一个数。
比如:
12345->12354
12543->12543
12354->12435
12435->12453
2 思路
可分成三种情况进行分析,
-
当数字组合已经是逆序排列时,比如:
54321
,已经是所有数字组合中的最大值,直接返回原数。 -
当数字组合的倒数两位是顺序排列时,比如:
12345
、13245
、14523
,直接将最后两位交换位置即可。即12345
->12354
、13245
->13254
、14523
->14532
。 -
当不是上述两种情况时,即边界值在数字排列的中间,比如:
12543
、13542
。- 先找出边界值的索引下标,如
12543
的边界值是5
,索引时2
,边界值的前一位(即小于边界值的第一位)的索引时2-1=1
; - 在边界值的右边找到大于边界值左边第一位的数,并将其交换, 如
12543
直接将最后一位数3
和边界左边第一位数2
交换即可,因为3>2
;如13542
则需要向前遍历,因为2<3
,所以交换4
和2
。 - 交换完之后,在将边界左边第一位数的右边的所有数按从小到大的顺序排列,因为要仅仅大于当前数,如
12543
->13245
、13542
->14235
。
- 先找出边界值的索引下标,如
3 Java代码实现
import java.util.Arrays;
public class FindNextestNumber {
public int[] findNestestNumber(int[] nums) {
if (nums.length < 2)
return nums;
for (int i = nums.length-1;i >0 ; i--) {
/**
* 分两种情况,第一种情况,
* 比如:12345,最后一位的数刚好大于第(n-2)位数,则只需要交换第(n-1)和(n-2)位置上的数即可
*
* 第二种情况:
* 比如:12543, 大于前面一面的数不在最后而在中间,所以需要知道其边界,并交换
*/
int t=0;
// 如果小于则继续
if (nums[i] < nums[i-1])
continue;
//极端情况1:最后两位刚好是顺序排列的
if (i==nums.length-1){
t = nums[i];
nums[i] = nums[i-1];
nums[i-1]=t;
break;
}
//极端情况2 刚好是倒序排列的
if (i==0)
break;
i--;//此时得到的是边界处的索引,所以i需要-1
for (int j = nums.length-1; j >i ; j--) {
if(nums[j] > nums[i]){
t = nums[i];
nums[i]=nums[j];
nums[j]=t;
break;
}
}
int start = i+1;
for (int j = start; j < nums.length-1; j++) {
for (int k = start; k < nums.length-i; k++) {
if (nums[k] > nums[k+1]){
t = nums[k];
nums[k]=nums[k+1];
nums[k+1]= t;
}
}
}
return nums;
}
return nums;
}
public static void main(String[] args) {
int[] nums = {1, 3,5,4,2};
System.out.println(Arrays.toString(nums));
FindNextestNumber findNextestNumber = new FindNextestNumber();
int[] res = findNextestNumber.findNestestNumber(nums);
System.out.println(Arrays.toString(res));
}
}