题目:
实现获取下⼀个排列的函数,算法需要将给定数组重新排列成字典序中下⼀个更⼤的排列。如果不存在下⼀个更⼤的排列,即为最大的排列,则将数字重新排列成最⼩的排列(即升序排列)。必须原地修改,只允许使⽤额外常数空间。
示例:
[2, 3, 5, 4, 1] -> [2, 4, 1, 3, 5]
要点:
- 多写几个例子,分析规律,尽量复杂一点,避免遗漏情况
- 规律:
- 找到从后往前第⼀个递减的值arr[x],同从右往左第一个大于它的值 进行交换
- 交换后arr[x]右侧仍然保持降序,故直接翻转arr[x]右侧即可
- 算法题一般不推荐使用内置的函数
- 不确定次数的循环常用while,写起来比for简单
// 原地生成下一个更大的排列
function nextPermutation(arr) {
// 边界情况
if (arr == null || arr.length <= 1) return;
let i = arr.length - 1;
while (i > 0 && arr[i] < arr[i - 1]) i--;
if (i > 0) {
// 找到交换位置i-1
let j = arr.length - 1;
// 一定能找到比arr[i-1]大的数
while (arr[j] <= arr[i - 1]) j--;
swap(arr, j, i - 1);
}
// 翻转arr[i-1]右侧
// 特殊情况——最大排列包含在下面
reverseRange(arr, i);
}
function swap(arr, i, j) {
let temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
function reverseRange(arr, i = 0, j = arr.length - 1) {
while (i < j) {
swap(arr, i++, j--);
}
}