31-Next-Permutation
Last updated
Was this helpful?
Last updated
Was this helpful?
实现获取下一个排列的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列。 如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列)。 必须原地修改,只允许使用额外常数空间。
测试用例:
1,2,3 → 1,3,2 3,2,1 → 1,2,3 1,1,5 → 1,5,1
想要获得下一个字典序,那么当前字典序变换到下一个字典序时,所带来的增量必须是最小的。所以:
我们需要从后往前找,找到第一个升序对。下标为[i,j]。此时nums[j]到nums[nums.length-1]一定是降序的。
然后在[j,end)找到第一个大于nums[i]的数nums[k],然后将nums[k],与nums[i]交换。此时nums[j]到nums[nums.length-1]仍然保持降序。
最后将[k,end)部分逆序,最后即为得到的答案。
如果没有找到升序对,那么直接逆序整个数组即可。
举个栗子: 对于序列12654
,找到第一个升序对之后,应该将2
与4
交换,得到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)区间逆序,得到字典序一定是最小的。
这个求下一个字典序的方法实在是妙啊,呜呜呜,为什么我就想不出来呢。不会吧不会吧。
总结:从后往前找,找到第一个升序对[i,j],然后在j及以后的区间找到第一个比nums[i]大的值,交换完后,逆序[j,end)即可。