【Leetcode】31. 下一个排列

106 阅读2分钟

题目描述

在这里插入图片描述

// 31. 下一个排列

// 实现获取 下一个排列 的函数,算法需要将给定数字序列重新排列成字典序中下一
// 个更大的排列。

// 如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列)。
// 必须 原地 修改,只允许使用额外常数空间。

题解


// 首先字典序的意思是,从升序排列开始,每一次排列后都找出,比上一次大的数中最小的数,
// 。比如[1, 3, 5, 6, 4],一下个排列就是[1, 3, 6, 4, 5],它是比原排列大的排列里面
// 最小的。找到下一个排列需要几个过程,如下:
// [1, 3, 5, 6, 4]
// >> [1, 3, 6, 5, 4]
// >> [1, 3, 6, 4, 5]
// 首先我们需要找到升序里面的最末位两个,把它们交换位置,变成[1, 3, 6, 5, 4],
// 此时如果这两个数的右数开始往右所有的数,本身就是升序(小在前大在后),那
// 当前这个排列就是最小的了,如果不是升序,我们要把它弄升序了,这时候排列就是
// 最小的了。
// 如果这个原排列本身全是升序,根据题意,我们直接把它逆序了。
// 
// 从nums倒叙遍历两个数nums[i]和nums[i + 1],如果出现升序,则i停止遍历,
// 此时最末位两个升序元素就是nums[i]和nums[i + 1]。
// 在保证i不小于0之后,倒叙遍历nums寻找右半部分比nums[i]大的数nums[j],
// 找到之后,交换nums[i]与nums[j],然后将i右半部的顺序反转。
// 
// 执行用时:1 ms, 在所有 Java 提交中击败了98.30%的用户
// 内存消耗:38.8 M, 在所有 Java 提交中击败了10.99%的用户
class Solution {
    public void nextPermutation(int[] nums) {
		int len = nums.length;
		int i = len - 2;
		while (i >= 0 && nums[i] >= nums[i + 1])
			i--;
		if (i >= 0) {
			int j = len - 1;
			while (j >= 0 && nums[i] >= nums[j]) {
				j--;
			}
			swap(nums, i, j);
		}
		reverse(nums, i + 1, len - 1);
    }
	
	private void swap(int[] arr, int i , int j) {
		int temp = arr[i];
		arr[i] = arr[j];
		arr[j] = temp;
	}
	
	private void reverse(int[] arr, int i, int j) {
		while (i < j) {
			swap(arr, i++, j--);
		}
	}
}