前言
本题主要考查 双指针 。
提示:以下是本篇文章正文内容,编程语言为Java
一、题目描述
整数数组的一个 排列 就是将其所有成员以序列或线性顺序排列。
例如,arr = [1,2,3] ,以下这些都可以视作 arr 的排列:[1,2,3]、[1,3,2]、[3,1,2]、[2,3,1] 。
整数数组的 下一个排列 是指其整数的下一个字典序更大的排列。更正式地,如果数组的所有排列根据其字典顺序从小到大排列在一个容器中,那么数组的 下一个排列 就是在这个有序容器中排在它后面的那个排列。如果不存在下一个更大的排列,那么这个数组必须重排为字典序最小的排列(即,其元素按升序排列)。
例如,arr = [1,2,3] 的下一个排列是 [1,3,2] 。
类似地,arr = [2,3,1] 的下一个排列是 [3,1,2] 。
而 arr = [3,2,1] 的下一个排列是 [1,2,3] ,因为 [3,2,1] 不存在一个字典序更大的排列。
给你一个整数数组 nums ,找出 nums 的下一个排列。
必须 原地 修改,只允许使用额外常数空间。
示例 1:
输入:nums = [1,2,3]
输出:[1,3,2]
链接:下一个排列
二、解题思路
分析排列可以看出,当数组所有元素都按照降序排列时,这个排列就是最大的了。也就是说,若存在相邻元素不是按照降序排列,那么该排列就不是一个最大的。
因为我们要找下一个排列,并且希望这个排列相比于上一个应当是增长最少的。因此,我们可以从低位向高位出发,依次比较相邻元素是否为降序,找到第一个不满足降序的 nums[i-1]
和 nums[i]
,此时 nums[i-1] < nums[i]
,我们想要让它变大,因此就需要将 nums[i-1]
替换为一个更大的数,这个数来自 nums[i...len-1]
。
同时,我们希望它变大的幅度最小,我们可以发现nums[i...len-1]
是满足降序的,所以我们再次从后向前遍历,找到第一个比 nums[i-1]
大的元素交换即可。
交换后,我们将 i
后面的重新按照升序排列,这样可以在保证新排列大于原来排列的情况下,使变大的幅度尽可能小。因为 i
后面的序列实际是降序的,所以我们直接用双指针法将其反转即可。
三、示例代码
class Solution {
public void nextPermutation(int[] nums) {
int a=-1;
//第一次遍历,找到需要交换的数
for(int i=nums.length-1;i>0;i--){
if(nums[i]>nums[i-1]){
a=i-1;
break;
}
}
//第二次遍历,交换。a=-1说明已经是最大排列了,直接反转就可以了
for(int i=nums.length-1;a!=-1&&i>0;i--){
if(nums[a]<nums[i]){
int tmp=nums[a];
nums[a]=nums[i];
nums[i]=tmp;
break;
}
}
//反转
int l=a+1;
int r=nums.length-1;
while(l<r){
int tmp=nums[l];
nums[l]=nums[r];
nums[r]=tmp;
l++;
r--;
}
}
}