类型:数组
-
- 下一个排列 💛
https://leetcode-cn.com/problems/next-permutation/
❓ 实现获取「下一个排列」的函数,算法需要将给定数字序列重新排列成「字典序」中下一个更大的排列。如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列)。必须 原地 修改,只允许使用额外常数空间。
💡 两遍扫描
我们希望找到一种方法,能够找到一个大于当前序列的新序列,且变大的幅度尽可能小。
- 我们需要将一个左边的「较小数」与一个右边的「较大数」交换,以能够让当前排列变大,从而得到下一个排列。
- 同时我们要让这个「较小数」尽量靠右,而「较大数」尽可能小。当交换完成后,「较大数」右边的数需要按照升序重新排列。这样可以在保证新排列大于原来排列的情况下,使变大的幅度尽可能小。
以排列 [4,5,2,6,3,1] 为例:
- 我们能找到的符合条件的一对「较小数」与「较大数」的组合为 2 与 3,满足「较小数」尽量靠右,而「较大数」尽可能小。
- 当我们完成交换后,排列变为 [4,5,3,6,2,1],此时我们可以重排「较小数」右边的序列,序列变为 [4,5,3,1,2,6].
算法描述如下:
- 首先从后向前查找第一个满足 a[i] < a[i+1] 的数。a[i] 即为最靠右的「较小数」。
- 经过上面的查找,我们可以得知 [i + 1, n) 必然是一个下降序列。我们在 [i + 1, n) 中从后向前找到第一个满足 a[i] < a[j] 的元素。a[j] 即是尽可能小的「较大数」。
- 交换 a[i] 与 a[j]。此时区间 [i + 1, n) 必为降序,我们可以直接使用双指针法反转 [i + 1, n) 使其变为升序。
如果在步骤 1 中找不到符合要求的「较小数」,说明当前序列已经是最大序列,跳过步骤 2,直接执行步骤 3,即可得到最小的升序序列。
class Solution: def nextPermutation(self, nums: List[int]) -> None: i = len(nums) - 2 while i >= 0 and nums[i] >= nums[i + 1]: i -= 1 if i >= 0: j = len(nums) - 1 while j >= 0 and nums[i] >= nums[j]: j -= 1 nums[i], nums[j] = nums[j], nums[i] left, right = i + 1, len(nums) - 1 while left < right: nums[left], nums[right] = nums[right], nums[left] left += 1 right -= 1时间复杂度:O(n),空间复杂度:O(1)