文章目录
题目
标题和出处
标题:下一个排列
出处:31. 下一个排列
难度
5 级
题目描述
要求
整数数组的一个排列是将其所有元素按序列或线性顺序排列。
- 例如, arr = [1,2,3] \texttt{arr = [1,2,3]} arr = [1,2,3],以下是 arr \texttt{arr} arr 的全部排列: [1,2,3] \texttt{[1,2,3]} [1,2,3]、 [1,3,2] \texttt{[1,3,2]} [1,3,2]、 [2,1,3] \texttt{[2,1,3]} [2,1,3]、 [2,3,1] \texttt{[2,3,1]} [2,3,1]、 [3,1,2] \texttt{[3,1,2]} [3,1,2]、 [3,2,1] \texttt{[3,2,1]} [3,2,1]。
整数数组的下一个排列 是指其整数的下一个字典序更大的排列。更正式的表述是,如果数组的所有排列根据其字典序从小到大排列在一个容器中,那么数组的下一个排列是在这个有序容器中排在它后面的那个排列。如果不存在下一个更大的排列,那么这个数组必须重排为字典序最小的排列(即,其元素按升序排列)。
- 例如, arr = [1,2,3] \texttt{arr = [1,2,3]} arr = [1,2,3] 的下一个排列是 [1,3,2] \texttt{[1,3,2]} [1,3,2]。
- 类似地, arr = [2,3,1] \texttt{arr = [2,3,1]} arr = [2,3,1] 的下一个排列是 [3,1,2] \texttt{[3,1,2]} [3,1,2]。
- 而 arr = [3,2,1] \texttt{arr = [3,2,1]} arr = [3,2,1] 的下一个排列是 [1,2,3] \texttt{[1,2,3]} [1,2,3],因为 [3,2,1] \texttt{[3,2,1]} [3,2,1] 不存在字典序更大的排列。
给定一个整数数组 nums \texttt{nums} nums,找出 nums \texttt{nums} nums 的下一个排列。
要求原地修改,只允许使用额外常数空间。
示例
示例 1:
输入: nums = [1,2,3] \texttt{nums = [1,2,3]} nums = [1,2,3]
输出: [1,3,2] \texttt{[1,3,2]} [1,3,2]
示例 2:
输入: nums = [3,2,1] \texttt{nums = [3,2,1]} nums = [3,2,1]
输出: [1,2,3] \texttt{[1,2,3]} [1,2,3]
示例 3:
输入: nums = [1,1,5] \texttt{nums = [1,1,5]} nums = [1,1,5]
输出: [1,5,1] \texttt{[1,5,1]} [1,5,1]
数据范围
- 1 ≤ nums.length ≤ 100 \texttt{1} \le \texttt{nums.length} \le \texttt{100} 1≤nums.length≤100
- 0 ≤ nums[i] ≤ 100 \texttt{0} \le \texttt{nums[i]} \le \texttt{100} 0≤nums[i]≤100
解法
思路和算法
如果数组 nums \textit{nums} nums 存在更大的排列,则一定存在两个下标 i i i 和 j j j 满足 i < j i < j i<j 且 nums [ i ] < nums [ j ] \textit{nums}[i] < \textit{nums}[j] nums[i]<nums[j]。为了找到下一个更大的排列,应取符合要求的最大的下标 i i i,在 nums [ i ] \textit{nums}[i] nums[i] 右侧寻找大于 nums [ i ] \textit{nums}[i] nums[i] 的最小元素并将该元素和 nums [ i ] \textit{nums}[i] nums[i] 交换,然后将 nums [ i ] \textit{nums}[i] nums[i] 右侧的全部元素按升序排序,即可得到下一个更大的排列。
如果数组 nums \textit{nums} nums 不存在更大的排列,则数组 nums \textit{nums} nums 单调递减,此时将整个数组反转得到单调递增的数组,即为下一个更大的排列。
具体做法如下。
-
反向遍历数组 nums \textit{nums} nums,找到符合 nums [ index 1 ] < nums [ index 1 + 1 ] \textit{nums}[\textit{index}_1] < \textit{nums}[\textit{index}_1 + 1] nums[index1]<nums[index1+1] 的最大下标 index 1 \textit{index}_1 index1。如果没有找到符合条件的下标 index 1 \textit{index}_1 index1,则 index 1 = − 1 \textit{index}_1 = -1 index1=−1。
-
如果 index 1 ≥ 0 \textit{index}_1 \ge 0 index1≥0,则找到符合 nums [ index 1 ] < nums [ index 2 ] \textit{nums}[\textit{index}_1] < \textit{nums}[\textit{index}_2] nums[index1]<nums[index2] 的最大下标 index 2 \textit{index}_2 index2,一定有 index 1 < index 2 \textit{index}_1 < \textit{index}_2 index1<index2,将 nums [ index 1 ] \textit{nums}[\textit{index}_1] nums[index1] 和 nums [ index 2 ] \textit{nums}[\textit{index}_2] nums[index2] 交换。如果 index 1 < 0 \textit{index}_1 < 0 index1<0 则不执行这一步。
-
将数组 nums \textit{nums} nums 从下标 index 1 + 1 \textit{index}_1 + 1 index1+1 到末尾的子数组反转(如果 index 1 = − 1 \textit{index}_1 = -1 index1=−1 则将整个数组反转),即可得到下一个排列。
证明
上述做法中,如果 index 1 < 0 \textit{index}_1 < 0 index1<0,则数组 nums \textit{nums} nums 中的每个元素都大于等于其后面的元素,因此数组 nums \textit{nums} nums 不存在更大的排列,下一个排列是将整个数组反转之后的结果。需要证明的是当 index 1 ≥ 0 \textit{index}_1 \ge 0 index1≥0 时上述做法得到的是下一个排列。
由于 index 1 \textit{index}_1 index1 是满足元素小于其后面的元素的最大下标,因此 nums [ index 1 ] \textit{nums}[\textit{index}_1] nums[index1] 右侧的元素均为单调递减,交换 nums [ index 1 ] \textit{nums}[\textit{index}_1] nums[index1] 右侧的元素不可能得到更大的排列。为了得到下一个更大的排列,必须在 nums [ index 1 ] \textit{nums}[\textit{index}_1] nums[index1] 右侧寻找大于 nums [ index 1 ] \textit{nums}[\textit{index}_1] nums[index1] 的最小元素,用 index 2 \textit{index}_2 index2 表示该最小元素所在下标,将 nums [ index 1 ] \textit{nums}[\textit{index}_1] nums[index1] 和 nums [ index 2 ] \textit{nums}[\textit{index}_2] nums[index2] 交换之后, nums [ index 1 ] \textit{nums}[\textit{index}_1] nums[index1] 替换成下一个更大的元素,符合下一个排列的规则。
在交换 nums [ index 1 ] \textit{nums}[\textit{index}_1] nums[index1] 和 nums [ index 2 ] \textit{nums}[\textit{index}_2] nums[index2] 之前, nums [ index 2 ] \textit{nums}[\textit{index}_2] nums[index2] 右侧的元素都小于等于 nums [ index 1 ] \textit{nums}[\textit{index}_1] nums[index1],下标范围 [ index 1 + 1 , index 2 − 1 ] [\textit{index}_1 + 1, \textit{index}_2 - 1] [index1+1,index2−1] 中的元素都大于 nums [ index 1 ] \textit{nums}[\textit{index}_1] nums[index1],且数组 nums \textit{nums} nums 从下标 index 1 + 1 \textit{index}_1 + 1 index1+1 到末尾的子数组单调递减,因此在交换 nums [ index 1 ] \textit{nums}[\textit{index}_1] nums[index1] 和 nums [ index 2 ] \textit{nums}[\textit{index}_2] nums[index2] 之后,数组 nums \textit{nums} nums 从下标 index 1 + 1 \textit{index}_1 + 1 index1+1 到末尾的子数组保持单调递减,将该子数组反转之后得到单调递增的子数组,符合下一个排列的规则。
因此上述做法得到的是下一个排列。
代码
java
class Solution {
public void nextPermutation(int[] nums) {
int length = nums.length;
int index1 = length - 2;
while (index1 >= 0 && nums[index1] >= nums[index1 + 1]) {
index1--;
}
if (index1 >= 0) {
int index2 = length - 1;
while (nums[index1] >= nums[index2]) {
index2--;
}
swap(nums, index1, index2);
}
reverse(nums, index1 + 1);
}
public void swap(int[] nums, int index1, int index2) {
int temp = nums[index1];
nums[index1] = nums[index2];
nums[index2] = temp;
}
public void reverse(int[] nums, int start) {
for (int i = start, j = nums.length - 1; i < j; i++, j--) {
swap(nums, i, j);
}
}
}
复杂度分析
-
时间复杂度: O ( n ) O(n) O(n),其中 n n n 是数组 nums \textit{nums} nums 的长度。需要反向遍历数组 nums \textit{nums} nums 最多两次,然后使用双指针反转子数组。
-
空间复杂度: O ( 1 ) O(1) O(1)。