题目:给出一个正整数,寻找全排列的下一个整数
思路:字典数算法。尽量保持高位不变,低位在最小范围内变换顺序。变换顺序的范围大小,取决于当前整数的逆序区域。
步骤:
1、从后向前查看逆序区域,找到逆序区域的前一位,也就是数组置换的边界
2、让逆序区域的前一位和逆序区域中大于它的最小的数字交换位置
3、把原来的逆序区域调整为顺序状态
时间复杂度:3个步骤中的时间复杂度都是O(n),所以整体复杂度是O(n)
/**
* 题目:给出一个正整数,寻找全排列的下一个整数
* 思路:字典数算法。尽量保持高位不变,低位在最小范围内变换顺序。变换顺序的范围大小,取决于当前整数的逆序区域。
* 步骤:
* 1、从后向前查看逆序区域,找到逆序区域的前一位,也就是数组置换的边界
* 2、让逆序区域的前一位和逆序区域中大于它的最小的数字交换位置
* 3、把原来的逆序区域调整为顺序状态
* <p>
* 时间复杂度:3个步骤中的时间复杂度都是O(n),所以整体复杂度是O(n)
*/
public class FindNearestNumber {
public static int[] getFindNearestNumber(int[] array) {
//1、从后向前查看逆序区域,找到逆序区域的前一位,也就是数字置换的边界
int index = findTransferPoint(array);
//如果数字置换边界是0,说明整个数组已经逆序,无法得到更大的相同数字组成的整数,返回null
if (index == 0) {
return null;
}
//2、让逆序区域的前一位和逆序区域中刚刚大于它的数字交换位置
//复制并入参,避免直接修改入参
int[] arrayCopy = Arrays.copyOf(array, array.length);
exchangeHead(arrayCopy, index);
//3、把原来逆序区域调整为顺序
reverse(arrayCopy, index);
return arrayCopy;
}
private static int findTransferPoint(int[] array) {
for (int i = array.length - 1; i > 0; i--) {
if (array[i] > array[i - 1]) {
return i;
}
}
return 0;
}
private static void exchangeHead(int[] array, int index) {
int head = array[index - 1];
for (int i = array.length - 1; i > 0; i--) {
if (head < array[i]) {
array[index - 1] = array[i];
array[i] = head;
break;
}
}
}
private static void reverse(int[] array, int index) {
for (int i = index; i < array.length - 1; i++) {
if (array[i] > array[i + 1]) {
int temp = array[i];
array[i] = array[i + 1];
array[i + 1] = temp;
}
}
}
public static void main(String[] args) {
int[] array = new int[]{1, 2, 3, 4, 5};
//打印12345后的10个全排列整数
for (int i = 0; i < 10; i++) {
array = getFindNearestNumber(array);
outputNumbers(array);
}
}
/**
* 输出数组
*/
private static void outputNumbers(int[] array) {
for (int i : array) {
System.out.print(i);
}
System.out.println();
}
}