寻找全排列的下一个数
    给出一个正整数,找出这个正整数所有数字全排列的下一个数。
    说通俗点就是在一个整数所包含数字的全部组合中,找到一个大于且仅大于原数的新整数。让我们举几个例子。
    如果输入12345,则返回12354。
    如果输入12354,则返回12435。
    如果输入12435,则返回12453。


    获得全排列下一个数的3个步骤。

    1. 从后向前查看逆序区域,找到逆序区域的前一位,也就是数字置换的边界。
    2. 让逆序区域的前一位和逆序区域中大于它的最小的数字交换位置。
    3. 把原来的逆序区域转为顺序状态。

    这种解法拥有一个“高大上”的名字:字典序算法

    1. public class FindNearestNumber {
    2. private static int findTransferPoint(int[] numbers) {
    3. for (int i = numbers.length - 1; i > 0; i--) {
    4. if (numbers[i] > numbers[i - 1]) {
    5. return i;
    6. }
    7. }
    8. return 0;
    9. }
    10. private static int[] exchangeHead(int[] numbers, int index) {
    11. int head = numbers[index - 1];
    12. for (int i = numbers.length - 1; i > 0; i--) {
    13. if (head < numbers[i]) {
    14. numbers[index - 1] = numbers[i];
    15. numbers[i] = head;
    16. break;
    17. }
    18. }
    19. return numbers;
    20. }
    21. private static int[] reverse(int[] num, int index) {
    22. for (int i = index, j = num.length - 1; i < j; i++, j--) {
    23. int temp = num[i];
    24. num[i] = num[j];
    25. num[j] = temp;
    26. }
    27. return num;
    28. }
    29. public static int[] findNearestNumber(int[] numbers) {
    30. // 从后向前查看逆序区域,找到逆序区域的前一位,也就是数字置换的边界
    31. int index = findTransferPoint(numbers);
    32. // 如果数字置换边界是 0,说明整个数组已经逆序,无法得到更大的相同数
    33. if (index == 0) {
    34. return null;
    35. }
    36. // 把逆序区的前一位和逆序区域中刚刚大于它的数字交换位置
    37. // 复制并入参,避免直接修改入参
    38. int[] numbersCopy = Arrays.copyOf(numbers, numbers.length);
    39. exchangeHead(numbersCopy, index);
    40. // 把原来的逆序区转为顺序
    41. reverse(numbersCopy, index);
    42. return numbersCopy;
    43. }
    44. public static void main(String[] args) {
    45. int[] num = {1, 2, 3, 4, 5};
    46. System.out.println(Arrays.toString(findNearestNumber(num)));
    47. }
    48. }

    时间复杂度字典序算法 - 图1