0031. 下一个排列
题目地址(31. 下一个排列)
https://leetcode-cn.com/problems/next-permutation/
题目描述
实现获取下一个排列的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列。
如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列)。
必须原地修改,只允许使用额外常数空间。
以下是一些例子,输入位于左侧列,其相应输出位于右侧列。
1,2,3 → 1,3,2
3,2,1 → 1,2,3
1,1,5 → 1,5,1
前置知识
回溯法
公司
阿里
腾讯
百度
字节
思路
符合直觉的方法是按顺序求出所有的排列,如果当前排列等于 nums,那么我直接取下一个但是这种做法不符合 constant space 要求(题目要求直接修改原数组),时间复杂度也太高,为 O(n!),肯定不是合适的解。
我们也可以以回溯的角度来思考这个问题,即从后往前思考。
让我们先回溯一次,即思考最后一个数字是如何被添加的。

由于这个时候可以选择的元素只有 2,我们无法组成更大的排列,我们继续回溯,直到如图:

我们发现我们可以交换 4 和 2 就会变小,因此我们不能进行交换。
接下来碰到了 1。 我们有两个选择:
1 和 2 进行交换
1 和 4 进行交换
两种交换都能使得结果更大,但是 和 2 交换能够使得增值最小,也就是题目中的下一个更大的效果。因此我们 1 和 2 进行交换。

还需要继续往高位看么?不需要,因为交换高位得到的增幅一定比交换低位大,这是一个贪心的思想。
那么如何保证增幅最小呢? 其实只需要将 1 后面的数字按照从小到大进行排列即可。
注意到 1 后面的数已经是从大到小排列了(非严格递减),我们其实只需要用双指针交换即可,而不需要真正地排序。
1 后面的数一定是从大到小排好序了吗?当然,否则,我们找到第一个可以交换的回溯点就不是 1 了,和 1 是第一个可以交换的回溯点矛盾。因为第一个可以交换的回溯点其实就是从后往前第一个递减的值。
关键点解析
写几个例子通常会帮助理解问题的规律
在有序数组中首尾指针不断交换位置即可实现 reverse
找到从右边起
第一个大于nums[i]的,并将其和 nums[i]进行交换
代码
语言支持: Javascript, Python3, CPP
JavaScript Code:
Python3 Code:
CPP Code:
相关题目
60.permutation-sequence(TODO)
最后更新于
这有帮助吗?