给出一个正整数,找出这个正整数所有数字全排列的下一个数。
如果输入 12345,则返回 12354。
如果输入 12354,则返回 12435。
如果输入 12435,则返回 12453。
例如给出整数 12354,它包含的数字是 1、2、3、4、5,如何找到这些数字全排列之后仅大于原数的新整数呢?
为了和原数接近,我们需要尽量保持高位不变,低位在最小的范围内变换顺序。
至于变换顺序的范围大小,则取决于当前整数的逆序区域。

如图所示,12354 的逆序区域是最后两位,仅看这两位已经是当前的最大组合。若想最接近原数,又比原数更大,必须从倒数第 3 位开始改变。
怎样改变呢?12345 的倒数第 3 位是 3,我们需要从后面的逆序区域中找到大于 3 的最小的数字,让其和 3 的位置进行互换。

互换后的临时结果是 12453,倒数第 3 位已经确定,这个时候最后两位仍然是逆序状态。我们需要把最后两位转变为顺序状态,以此保证在倒数第 3 位数值为 4 的情况下,后两位尽可能小。

这样一来,就得到了想要的结果 12435。
获得全排列下一个数的 3 个步骤,也称为字典序算法
- 从右往左,找出第一个左边小于右边的数
- 让逆序区域的前一位和逆序区域中大于它的最小的数字交换位置。
- 把原来的逆序区域转为顺序状态 。
function findNearestNumber(numbers){//1.从后向前查看逆序区域,找到逆序区域的前一位,也就是数字置换的边界let index = findTransferPoint(numbers);//如果数字置换边界是0,说明整个数组已经逆序,无法得到更大的相同数//字组成的整数,返回nullif(index == 0){return null;}let numbersCopy = [...numbers];//2.把逆序区域的前一位和逆序区域中刚刚大于它的数字交换位置exchangeHead(numbersCopy, index);//3.把原来的逆序区域转为顺序reverse(numbersCopy, index);return numbersCopy;}function findTransferPoint(numbers){// 1.从右往左,找出第一个左边小于右边的数,比如12354,那么i就是5,i后边的区域称为逆序区域for(let i=numbers.length-1; i>0; i--){if(numbers[i-1] < numbers[i]){return i;}}return 0;}function exchangeHead(numbers, index){let head = numbers[index-1];// i左边的数,比如12354,i是5,head就是3//2.从右往左,找出第一个大于i左边的数,并交换位置for(let i=numbers.length-1; i>0; i--){if(numbers[i] > head){numbers[index-1] = numbers[i];numbers[i] = head;break;}}return numbers;}function reverse(num, index){//3.i之后的从小到大排列num = [...num.slice(0, index), ...num.slice(index).sort((a, b) => a-b)]}
