大家好!我是曾续缘🤗
今天是《LeetCode 热题 100》系列
发车第 99 天
技巧第 4 题
❤️点赞 👍 收藏 ⭐再看,养成习惯
下一个排列 整数数组的一个 排列 就是将其所有成员以序列或线性顺序排列。
- 例如,
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]示例 2:
输入:nums = [3,2,1] 输出:[1,2,3]示例 3:
输入:nums = [1,1,5] 输出:[1,5,1]提示:
难度:💖💖
1 <= nums.length <= 100
0 <= nums[i] <= 100
解题方法
下一个排列是一个经典的算法问题,要求我们找出给定整数数组的下一个字典序更大的排列。如果当前排列已经是最大可能的排列,那么我们需要找到最小的排列,即所有数字按照升序排列。这个问题要求我们原地修改数组,并且只能使用常数空间。
解题步骤
步骤1:从后向前查找递减序列
我们从数组的最后一个元素开始向前查找,找到第一个满足nums[i] < nums[i+1]
的元素nums[i]
。这个元素是可以增大的最小值了。
步骤2:找到比nums[i]
大的最小元素
从数组的最后一个元素开始向前查找,找到第一个满足nums[j] > nums[i]
的元素nums[j]
。这个元素将会和nums[i]
交换。
步骤3:交换nums[i]
和nums[j]
交换nums[i]
和nums[j]
,这样就得到了一个新的排列,nums[i]
变大了,变大的尽可能的小,为nums[j]
。但还没有结束。
步骤4:反转nums[i+1]
到末尾的序列
由于nums[i+1]
到数组末尾的序列是降序排列的,我们需要将其反转,使其成为升序排列,变得 最小。
Code
public class Solution {public void nextPermutation(int[] nums) {// 从后向前查找递减序列int i = nums.length - 2;while (i >= 0 && nums[i] >= nums[i + 1]) {i--;}// 如果找到递减序列,则进行下一步查找if (i >= 0) {// 找到比nums[i]大的最小元素int j = nums.length - 1;while (j >= 0 && nums[i] >= nums[j]) {j--;}// 交换nums[i]和nums[j]swap(nums, i, j);}// 反转nums[i+1]到末尾的序列reverse(nums, i + 1, nums.length - 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 start, int end) {// 反转数组的一部分while (start < end) {swap(arr, start, end);start++;end--;}}
}