31-Next-Permutation

0x1 题目详情

原题链接

实现获取下一个排列的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列。 如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列)。 必须原地修改,只允许使用额外常数空间。

测试用例:

1,2,3 → 1,3,2 3,2,1 → 1,2,3 1,1,5 → 1,5,1

0x2 解题思路

想要获得下一个字典序,那么当前字典序变换到下一个字典序时,所带来的增量必须是最小的。所以:

  1. 我们需要从后往前找,找到第一个升序对。下标为[i,j]。此时nums[j]到nums[nums.length-1]一定是降序的。

  2. 然后在[j,end)找到第一个大于nums[i]的数nums[k],然后将nums[k],与nums[i]交换。此时nums[j]到nums[nums.length-1]仍然保持降序。

  3. 最后将[k,end)部分逆序,最后即为得到的答案。

  4. 如果没有找到升序对,那么直接逆序整个数组即可。

举个栗子: 对于序列12654,找到第一个升序对之后,应该将24交换,得到14256,而不是直接交换升序对得到结果16254

下面我们来证明一下:

因为(nums[i],nums[j])是第一个升序对,所以有:$nums[i]nums[i]>=nums[k+1]$及以后的值,因为[j,end)区间是降序的,且有j>=k。

所以有$nums[j]>nums[k-1]>nums[i]>=nums[k+1]$,所以在[j,end)区间数组仍是降序的,此时将[j,end)区间逆序,得到字典序一定是最小的。

0x3 代码实现

0x4 课后总结

这个求下一个字典序的方法实在是妙啊,呜呜呜,为什么我就想不出来呢。不会吧不会吧。

总结:从后往前找,找到第一个升序对[i,j],然后在j及以后的区间找到第一个比nums[i]大的值,交换完后,逆序[j,end)即可。

Last updated

Was this helpful?