1. 问题描述:
实现获取下一个排列的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列。
如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列)。
必须原地修改,只允许使用额外常数空间。
以下是一些例子,输入位于左侧列,其相应输出位于右侧列。
1,2,3 → 1,3,2
3,2,1 → 1,2,3
1,1,5 → 1,5,1
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/next-permutation
2. 思路分析:
① 题目还是比较好理解的,比当前数组序列大的下一个排列,一开始的时候想到时候递归的方法求解出有序的全排列,然后使用循环进行扫描匹配看下一个更大一点的排列是什么,显然这种方法是效率很低的,看了领扣的官方题解之后,发现他们的思路实在是太棒了,然后自己模仿他们写了一遍代码,可以学习一下这样的思路
② 首先他们是从数组的最右端开始扫描,找到从右向左递增的递增序列,比如官方给出的例子中,158476531的数组序列,可以知道从右边往左边扫描的过程中发现13657是递增的序列,而到4的时候则不是递增的序列了,因为4大于了7,所以这个时候循环结束,循环变量记录了4这个位置,在后面递增的序列中从右往左找到第一个比4大的位置可以知道是13657中的5对应的位置,这个时候需要将4的位置与5的位置进行互换,这样的话在高位的时候就搞定了,因为调换元素之后那么剩下来的从左到右是递增的,所以需要进行翻转,应该是从4这个位置后面进行翻转,这样形成的数字序列才是下一个更大的排列
这个可以自己使用测试用例直接在idea中进行调试,可以一步步看到代码执行过程中数组元素的变换以及变量的变化
158476531
交换4与5的位置
158576431
进行数组元素的翻转:
158513467
可以在对应的方法中打上断点,一步步点击蓝色的箭头可以看到执行的具体过程以及变量的变化
3. 代码如下:
import java.util.Scanner;
public class Solution {
/*先是需要找到从右往左递增的序列, 这个是要debug调试运行的话会非常方便*/
public void nextPermutation(int[] nums) {
int i = nums.length - 2, j = nums.length - 1;
/*找到从右往左递增的序列*/
while(i >= 0 && nums[i] >= nums[i + 1]) --i;
if (i >= 0){
/*在i位置后面的有序序列中找到比i位置大的位置*/
while (j >= 0 && nums[j] <= nums[i]) --j;
/*j位置对应的就是在有序序列中第一个比i位置大的位置, 交换两个元素的位置*/
swap(nums, i, j);
}
/*将i + 1位置的元素进行翻转即可*/
reverse(nums, i + 1);
}
public void reverse(int[] nums, int i) {
int j = nums.length - 1;
while (i < j){
swap(nums, i, j);
++i;
--j;
}
}
public static void swap(int[] nums, int i, int j) {
int t = nums[i];
nums[i] = nums[j];
nums[j] = t;
}
}