LeetCode刷题记录----31.下一个排序(Medium)
2025/10/1
题目(Medium):
31.下一个排序
解题思路:
我们先看按字典顺序排列的[1,2,3]的全排列顺序:
[1,2,3]
[1,3,2]
[2,1,3]
[2,3,1]
[3,1,2]
[3,2,1]
可以看出来,每一个都比之前的大一点,但是大的幅度又控制的尽可能小。比如[2,1,3]这里,如果把3放到开头那肯定能比之前的大,但是那增大的幅度会太多了,放在比元素2小的元素1的地方同样可以得到更大的排序,但是这样增大的幅度会更小,也就更有可能是我们要求的下一个排序。
因此,我们大致可以按以下思路去考虑,如果是下一个排序要确保:
①要找到一个尽可能靠右,又尽可能小的的较小数
②要找到一个尽可能靠右,在较小数右边,且比较小数大的第一个较大数
③在找到最小和最大数了之后,可以交换它们。交换了之后为了使得字典序尽可能小,要让较大数交换到的位置的后面的元素按升序排列。
如果确保了以上三点,那大概得到的数组就是我们要求的下一个排序的。
那这个较小数要怎么找呢?我们可以考虑倒着遍历数组,找到第一个不在降序排列中的元素。也就是找到第一个nums[i] < nums[i+1]的 i 的位置的元素

那较大数怎么找呢?同样倒着遍历数组,找到降序部分中,第一个比 较小数 大的元素即可。

之后我们交换较大数和较小数,并把 i 索引位置后的元素都翻转即可(因为我们可以看出来这部分本身已经是降序排列的了,我们直接通过双指针来交换首尾元素即可 )
那如果第一步找不到最小数,整个数组从0到n-1都是降序的怎么办呀?那说明此时已经是该数组的最大字典序,直接从0到n-1部分都翻转即可。
具体代码如下:
public class Solution {public void NextPermutation(int[] nums) {int n = nums.Length;if(n <= 1) return;//1.首先找到较小的数(倒着第一个非降序的元素)int i = n-2;while(i >= 0 && nums[i] >= nums[i+1]){i--;}//2.找到较大的数(倒着遍历发现的第一个比 较小数 大的元素)if(i >= 0){int j = n-1;while(j >= 0 && nums[i] >= nums[j]){j--;}Swap(nums, i, j);}//把较小数位置后的元素进行翻转Reverse(nums, i+1);}private void Swap(int[] nums, int i, int j){if(i == j) return;int temp = nums[i];nums[i] = nums[j];nums[j] = temp;}private void Reverse(int[] nums, int startIndex){//因为此时[startIndex, nums.Length-1]这个范围的元素本身是降序排序的//所以不用特意去排序用双指针来首尾交换即可int left = startIndex, rigth = nums.Length - 1;while(left < rigth){Swap(nums, left, rigth);left++;rigth--;}}
}
时间复杂度:O(N)
空间复杂度:O(1)
总结:
①对于这种要从一个状态变成另一个状态的题目,我们要观察两个状态之间的相同和不同的 地方。找到导致变化的原因,再进而去思考能够让这个变化产生的限制条件
②这里变化到下一个排序的思考方向在于既要比当的大,又不能变化的太大。所以先考虑让他变大(找到较小数和较大数进行交换位置),然后再继续考虑让交换后的不影响当前变大结果的部分尽可能小。