下一个排列
实现获取下一个排列的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列。
如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列)。 必须原地修改,只允许使用额外常数空间。
以下是一些例子,输入位于左侧列,其相应输出位于右侧列。 1,2,3 → 1,3,2 3,2,1 → 1,2,3 1,1,5 → 1,5,1
思路分析
①是否存在更大的排列
更大的排列
考虑最大的字典序排列: 降序排列 [1,2,3] → [3,2,1] 对于 [3,2,1] 序列,已经是最大字典序了
假如序列存在一个更大的排列,那它必然不是降序排列 因此判断是否存在下一个排列的条件就是 顺序遍历数组,判断是否完全降序
②找到下一个排列
首先对于[1,2,3,4,5,6],假如我们要人工找到下一个排列,我们知道要把倒数两位调换一下[1,2,3,4,6,5],这样值的变动最小,字典序大小变动也最小.
为什么最后两位调换之后字典序会变大呢?
我们可以发现一个本质: 它们是升序的, 升序排列那么必然就存在可以调换成降序的操作空间,因此可以改动升序关系的任意两位来获取一个更大的字典序 如 [1,2,5,4,3,6]
知道了获得更大序的方法,接下来我们要确定什么操作能得到最小的更大序(下一个更大的序列)
其实字典序类似于数的大小关系. 比如[1,2,3] → [2,1,3][1.3.2]
所以为了找到最小的更大序列,我们操作的升序数对要尽可能的小.所以目标就变成了:
找到最靠后的一对升序数对
[9,8,3,6,5,4]→[9,8,4,3,5,6] 最靠后的/最小的 升序数对是 [3,4],初步调换后是[9,8,4,6,5,3] 显然这个结果还不太对.
找到了最小的升序数对只是保证了在一步操作的范围内,我们增加的值是最小的. 换句话说,其实再多加几步操作才能保证是下一个序列. 来看看我们还差些什么 [9,8,4,6,5,3] →[9,8,4,3,5,6] , 4的后面原本是降序,被整理成了升序
首先在我们的算法里,我们从后往前找一个升序的"峰值" 换句话说,我们在找到""峰值""之前,也即从末尾到"峰值"",必然是降序的,也就是局部最大的序列. 因此我们调换了一对最小的升序对,整个序列在""峰值""之前已经是最小的了, 但在调换位置之后的局部仍然是降序,即现在的序是前半段最小+后半段最大, 因此将""峰值""往后调整成升序,即后半段最小即可构成"最小+最小"的下一个排列.
题解代码
1 | class Solution { |