持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第2天,点击查看活动详情
1.描述
整数数组的一个 排列 就是将其所有成员以序列或线性顺序排列。
例如,arr = [1,2,3] ,以下这些都可以视作 arr 的排列:[1,2,3]、[1,3,2]、[3,1,2]、[2,3,1] 。 整数数组的 下一个排列 是指其整数的下一个字典序更大的排列。更正式地,如果数组的所有排列根据其字典顺序从小到大排列在一个容器中,那么数组的 下一个排列 就是在这个有序容器中排在它后面的那个排列。如果不存在下一个更大的排列,那么这个数组必须重排为字典序最小的排列(即,其元素按升序排列)。
例如,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 的下一个排列。
必须 原地 修改,只允许使用额外常数空间。
示例 1:
输入: nums = [1,2,3]
输出: [1,3,2]
2.思路
本题需要我们找到指定数组的下一个更大字典序排列,那么首先我们需要明白什么是更大字典序排列,我的个人理解就是将所有数字排列组合以后按照升序排列,而我们又需要找到下一个更大排列,那就意味着我们需要找到离其最近的,改动最小的那个更大排列。
最简单的方法就是我们将这个数组继续一个全排列,把每一个组合都列出来,然后我们只需要找到指定数组在排列中的位置,然后获取下一个就好了。但是这种方法的性能开销会比较的大。我们有没有一种更好的实现方式呢,我们能不能在不列出全部数组的情况下获取指定数组的下一个更大排列。
更大排列从数组上来说,我们可以认为是将后面的大数字与前面的小数字进行一个交换,就可以得到一个更大的数字。然后我们需要找到最近的那个更大的数字,那么我们就需要找到更后面的那个更大数字与它距离最近的更小数字来做交换,这样我们数字的变动幅度就会下降。
于是我们从后往前找到一个数字大于它前面的数字,那么前面这个较小数字,就是我们从后往前的过程中找到的第一个能够使用的最小数字,然后我们确定它的位置,再从最后一个数字开始寻找第一个比该数字大的数字,然后交换位置以达到最小变化幅度的目的。
但是只靠交换还不能达到最小变化幅度的目的,因为在交换之后,最小位置之后的数字很有可能是个逆序排列,所以我们需要再对该位置之后的数字进行一次升序排列,以达到我们最小变化幅度的需求。这样操作下来,我们就得到了下一个更大排列
const nextPermutation = (nums) => {
let i = nums.length - 2;
let j = nums.length - 1;
let k = nums.length - 1;
while (i >= 0 && nums[i] >= nums[j] ) {
i--;
j--;
}
if (i < 0) return nums.reverse();
while (nums[k] <= nums[i]) {
k--;
}
[nums[i], nums[k]] = [nums[k], nums[i]];
for (let l = nums.length - 1; j < l; ++j, --l) {
[nums[j], nums[l]] = [nums[l], nums[j]];
}
return nums;
};