实现获取 下一个排列 的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列。
如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列)。
必须 原地 修改,只允许使用额外常数空间。
示例 1:
输入:nums = [1,2,3]
输出:[1,3,2]
示例 2:
输入:nums = [3,2,1]
输出:[1,2,3]
示例 3:
输入:nums = [1,1,5]
输出:[1,5,1]
示例 4:
输入:nums = [1]
输出:[1]
提示:
1 <= nums.length <= 100
0 <= nums[i] <= 100
思路:
按照字典序希望得到下一个比较大的排列,则需要将后面的大数与前面的小数交换,就可以得到一个更大的序列,如123456,将5,6交换就可以得到更大的序列123465。
同时我们需要增加的幅度尽可能小,于是我们需要:
1.从尽可能靠右的部分进行交换,即从后向前查找。
2.将一个尽可能小的大数与前面的小数进行交换,如123465应当交换4,5 而不是6,5。
3.将大数换到前面后,将大数后面的数重置为最小的序列,即升序。
算法步骤:
1.从后向前查找第一个顺序对(i,i+1),满足num[i]<nums[i+1],则此时较小的数为num[i],同时,[i+1,n)区间必定为降序序列。
2.在区间[i+1,n)中从后向前查找第一个元素j,满足a[i]<a[j],则较大数为a[j]。
3.交换nums[i],nums[j],此时区间[i+1,n)为降序,反转区间[i+1,n),使其变为升序,并且无需排序。
特殊情况:如果第一步没有找见,则说明整个序列为降序,已经是最大的了,直接反转即为最小的序列。
eg:
nums=[1,2,3,8,5,7,6,4]
1.寻找第一个升序对,此时i=5,升序对[5,7]
2.在[i+1,n)中寻找第一个大于i的数,即j=6 nums[j]=6
3.交换nums[i],nums[j],nums=[1,2,3,8,6,7,5,4],此时[i+1,j)为降序
4.反转[i+1,n) nums=[1,2,3,8,6,4,5,7]即为结果。
AC代码(C++):
class Solution {
public:
void nextPermutation(vector<int>& nums) {
int len = nums.size();
int i = len - 2;
while (i >= 0 && nums[i] >= nums[i + 1]) i--; //找见第一个升序的i
if (i >= 0) {
int j = len - 1;
while (j >= 0 && nums[j] <= nums[i]) j--; //找见第一个大于nums[i]的元素
swap(nums[i], nums[j]);
}
reverse(nums.begin() + i + 1, nums.end());
}
};