前言
今天解决Leetcode题库的第31题—下一个排列。这是一道比较经典的中档题,可以采用指针的方法。当然也是暴力排列组出来,但非常不推荐,即使能出效果也有很大概率会超时。
题意速通
这道题主要意思是:给定一个排列,输出下一个字典序比当前大的一个序列,就如 1,2,3 下一个字典序较大的就是 1,3,2.当指定的字典序达到最大序列的时候就输出重置为最小的那一个序列.就如:3,2,1 下一个字典序较大的就是 1,2,3.这题主要的难点就是如何找到比给定序列大一点的序列,这期间就要讲究搜索技巧了,暴力穷举可以解决小数量序列,但数列一大就会超时。
思路分析
对于指定序列,我们首先要找到序列中的升序子序列,如下图:
从后往前进行搜索最近的一个最小子序列,至于如何搜索就是用两个指针进行从后往前进行遍历搜索,如下图:
找到最高位也就是7的位置,也是最近的升序列,一个指针指到7,另一个指针往后遍历,检查哪个数之比7大一点,也就是比7大的数中最接近7的那个数。但在查找的时候我们可以先找比7小的数,因为后续序列都是从大到小的排序的,所以只需要找到第一个比7小的数的前一位就一定是比7大且最接近7的数。如下图:
最后一步只需要把现任最高位上的9之后的序列进行一个从小到大的排序。两指针只需要一个在左一个在右边比较边移动就可以将数组排序完
最后的结果就是比指定序列稍大的序列,也就是符合题意的下一个排列
代码实现(JAVA实现)
public void nextPermutation(int[] nums){
int len=nums.length;
int k=len-2;
//从后往前找到升序子序列
while (k>=0 && nums[k]>=nums[k+1])
k--;
//特殊情况:如果整个数组元素都是降序排列的
if (k==-1){
Arrays.sort(nums);
return;
}
//寻找最高位后比k位小的值,再向后退一位找到比k位上的值稍大的数值
int i=k+2;
while (i<len && nums[i] > nums[k])
i++;
//找到上述值就交换
int temp=nums[k];
nums[k]=nums[i-1];
nums[i-1]=temp;
//将k位(最高位)后的序列进行从小到大的排序
int start = k + 1;
int end = len - 1;
while (start < end){
int reTemp=nums[start];
nums[start] = nums[end];
nums[end] = reTemp;
start++;
end--;
}
}
结语
其实理解上述的图文解说,在代码方面也就是打字的快慢的问题了,此题解法是最经典的二指针法,当然这解法不限于此题。重点在于理解此题的核心因素,要找到最小升序子序列,然后在与升序子序列最接近的高位进行交换。