持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第5天,点击查看活动详情
下一个排列
整数数组的一个排列,就是将其所有成员以序列或线性顺序排列。
例如有一串数字,123,它的字典序是123,132,213,231,312,321。所谓整数数组字典序的下一个排列,就是指找到数组的一个排序,使其组成的数比当前数大的最小的数。
例如,arr = [1,2,3] 的下一个排列是 [1,3,2] 。
类似地,arr = [2,3,1] 的下一个排列是 [3,1,2] 。
而 arr = [3,2,1] 的下一个排列是 [1,2,3] ,因为 [3,2,1] 不存在一个字典序更大的排列。 给你一个整数数组 nums ,找出 nums 的下一个排列。 必须 原地 修改,只允许使用额外常数空间。
解析
我们带入一个稍长的例子进行讲解:[2,7,6,3,5,4,1]的下一个排列是什么?即比2763541大的最小数是多少?
- 步骤1: 2763541 [找最后一个正序35]
- 步骤2 : 2763541 [找3后面比3大的最后一个数]
- 步骤3: 2764531 [交换3,4的位置]
- 步骤4: 2764135 [把4后面的531反序排列为135即得到最后的排列(q)]
可得比2763541大的最小数:2764135。
总结
先遍历数组找到最后一个正序
for (int i = 0; i < nums.length - 1; i++) {
//找到最后的两个正序
if (nums[i] < nums[i + 1]) {
local = i;
}
}
找到比正序的第一个数字大的最后一个数
for (int j = local + 2; j < nums.length; j++) {
if (nums[local] < nums[j] && nums[j] <= nums[k]) {
k = j;
}
}
交换两数的位置
public static void swap(int[] nums, int l, int r) {
int temp = nums[l];
nums[l] = nums[r];
nums[r] = temp;
}
将该位置以后的数组反序
public static void change(int[] nums, int l, int r) {
while (l < r) {
swap(nums, l++, r--);
}
}
代码
public static void next(int[] nums) {
int local = -1;
for (int i = 0; i < nums.length - 1; i++) {
//找到最后的两个正序
if (nums[i] < nums[i + 1]) {
local = i;
}
}
if (local == -1) {
change(nums, 0, nums.length - 1);
} else {
//此时的i是最后一个正序
int k = local + 1;
//找到两个正序中的第一个,后面比他大的最小数,交换
for (int j = local + 2; j < nums.length; j++) {
if (nums[local] < nums[j] && nums[j] <= nums[k]) {
k = j;
}
}
swap(nums, local, k);
//将该位置后的数反序
change(nums, local + 1, nums.length - 1);
}
}
public static void change(int[] nums, int l, int r) {
while (l < r) {
swap(nums, l++, r--);
}
}
public static void swap(int[] nums, int l, int r) {
int temp = nums[l];
nums[l] = nums[r];
nums[r] = temp;
}