双指针 数组 难度 中等
题目描述 整数数组的一个 排列 就是将其所有成员以序列或线性顺序排列。
例如,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 解法 方法一:两次遍历 思考
若生成全部排列再取当前序列的后继,时间复杂度为 \(O(n!)\) 。 \(n \le 100\) ,无法通过,且题目要求原地修改、仅使用常数额外空间。
我们并不需要全集,只需字典序中紧邻的下一个。下一个排列必须严格大于当前序列,且改动应尽量靠右、幅度尽量小。
注意到,最长降序后缀已经是该段能排出的最大形态;它左侧的 \(\textit{nums}[i]\) 才是需要抬高的枢轴。后缀里刚好比 \(\textit{nums}[i]\) 大的数位于最右侧,交换后再将后缀翻成升序,改动便落在最右边。若整段均为降序,则不存在更大的排列,反转即回到最小排列。
我们先从后往前遍历数组 \(\textit{nums}\) ,找到第一个满足 \(\textit{nums}[i] \lt \textit{nums}[i + 1]\) 的位置 \(i\) ,那么 \(\textit{nums}[i]\) 就是我们需要交换的元素,而 \(\textit{nums}[i + 1]\) 到 \(\textit{nums}[n - 1]\) 的元素是一个降序序列。
接下来,我们再从后往前遍历数组 \(\textit{nums}\) ,找到第一个满足 \(\textit{nums}[j] \gt \textit{nums}[i]\) 的位置 \(j\) ,然后我们交换 \(\textit{nums}[i]\) 和 \(\textit{nums}[j]\) 。最后,我们将 \(\textit{nums}[i + 1]\) 到 \(\textit{nums}[n - 1]\) 的元素反转,即可得到下一个排列。
时间复杂度 \(O(n)\) ,空间复杂度 \(O(1)\) 。其中 \(n\) 为数组的长度。
Python3 Java C++ Go TypeScript Rust JavaScript C# PHP
class Solution :
def nextPermutation ( self , nums : list [ int ]) -> None :
n = len ( nums )
i = next (( i for i in range ( n - 2 , - 1 , - 1 ) if nums [ i ] < nums [ i + 1 ]), - 1 )
if ~ i :
j = next (( j for j in range ( n - 1 , i , - 1 ) if nums [ j ] > nums [ i ]))
nums [ i ], nums [ j ] = nums [ j ], nums [ i ]
nums [ i + 1 :] = nums [ i + 1 :][:: - 1 ]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 class Solution {
public void nextPermutation ( int [] nums ) {
int n = nums . length ;
int i = n - 2 ;
for (; i >= 0 ; -- i ) {
if ( nums [ i ] < nums [ i + 1 ] ) {
break ;
}
}
if ( i >= 0 ) {
for ( int j = n - 1 ; j > i ; -- j ) {
if ( nums [ j ] > nums [ i ] ) {
swap ( nums , i , j );
break ;
}
}
}
for ( int j = i + 1 , k = n - 1 ; j < k ; ++ j , -- k ) {
swap ( nums , j , k );
}
}
private void swap ( int [] nums , int i , int j ) {
int t = nums [ j ] ;
nums [ j ] = nums [ i ] ;
nums [ i ] = t ;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 class Solution {
public :
void nextPermutation ( vector < int >& nums ) {
int n = nums . size ();
int i = n - 2 ;
while ( ~ i && nums [ i ] >= nums [ i + 1 ]) {
-- i ;
}
if ( ~ i ) {
for ( int j = n - 1 ; j > i ; -- j ) {
if ( nums [ j ] > nums [ i ]) {
swap ( nums [ i ], nums [ j ]);
break ;
}
}
}
reverse ( nums . begin () + i + 1 , nums . end ());
}
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 func nextPermutation ( nums [] int ) {
n := len ( nums )
i := n - 2
for ; i >= 0 && nums [ i ] >= nums [ i + 1 ]; i -- {
}
if i >= 0 {
for j := n - 1 ; j > i ; j -- {
if nums [ j ] > nums [ i ] {
nums [ i ], nums [ j ] = nums [ j ], nums [ i ]
break
}
}
}
for j , k := i + 1 , n - 1 ; j < k ; j , k = j + 1 , k - 1 {
nums [ j ], nums [ k ] = nums [ k ], nums [ j ]
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 function nextPermutation ( nums : number []) : void {
const n = nums . length ;
let i = n - 2 ;
while ( i >= 0 && nums [ i ] >= nums [ i + 1 ]) {
-- i ;
}
if ( i >= 0 ) {
for ( let j = n - 1 ; j > i ; -- j ) {
if ( nums [ j ] > nums [ i ]) {
[ nums [ i ], nums [ j ]] = [ nums [ j ], nums [ i ]];
break ;
}
}
}
for ( let j = n - 1 ; j > i ; -- j , ++ i ) {
[ nums [ i + 1 ], nums [ j ]] = [ nums [ j ], nums [ i + 1 ]];
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 impl Solution {
pub fn next_permutation ( nums : & mut Vec < i32 > ) {
let n = nums . len ();
let mut i = n ;
while i > 1 && nums [ i - 2 ] >= nums [ i - 1 ] {
i -= 1 ;
}
// nums[i-1..] is the longest non-increasing suffix; pivot is nums[i-1]
if i > 1 {
let pivot = i - 2 ;
let mut j = n - 1 ;
while nums [ j ] <= nums [ pivot ] {
j -= 1 ;
}
nums . swap ( pivot , j );
}
nums [ i - 1 .. ]. reverse ();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 /**
* @param {number[]} nums
* @return {void} Do not return anything, modify nums in-place instead.
*/
var nextPermutation = function ( nums ) {
const n = nums . length ;
let i = n - 2 ;
while ( i >= 0 && nums [ i ] >= nums [ i + 1 ]) {
-- i ;
}
if ( i >= 0 ) {
let j = n - 1 ;
while ( j > i && nums [ j ] <= nums [ i ]) {
-- j ;
}
[ nums [ i ], nums [ j ]] = [ nums [ j ], nums [ i ]];
}
for ( i = i + 1 , j = n - 1 ; i < j ; ++ i , -- j ) {
[ nums [ i ], nums [ j ]] = [ nums [ j ], nums [ i ]];
}
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 public class Solution {
public void NextPermutation ( int [] nums ) {
int n = nums . Length ;
int i = n - 2 ;
while ( i >= 0 && nums [ i ] >= nums [ i + 1 ]) {
-- i ;
}
if ( i >= 0 ) {
for ( int j = n - 1 ; j > i ; -- j ) {
if ( nums [ j ] > nums [ i ]) {
swap ( nums , i , j );
break ;
}
}
}
for ( int j = i + 1 , k = n - 1 ; j < k ; ++ j , -- k ) {
swap ( nums , j , k );
}
}
private void swap ( int [] nums , int i , int j ) {
int t = nums [ j ];
nums [ j ] = nums [ i ];
nums [ i ] = t ;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 class Solution {
/**
* @param integer[] $nums
* @return void
*/
function nextPermutation ( & $nums ) {
$n = count ( $nums );
$i = $n - 2 ;
while ( $i >= 0 && $nums [ $i ] >= $nums [ $i + 1 ]) {
$i -- ;
}
if ( $i >= 0 ) {
$j = $n - 1 ;
while ( $j >= $i && $nums [ $j ] <= $nums [ $i ]) {
$j -- ;
}
$temp = $nums [ $i ];
$nums [ $i ] = $nums [ $j ];
$nums [ $j ] = $temp ;
}
$this -> reverse ( $nums , $i + 1 , $n - 1 );
}
function reverse ( & $nums , $start , $end ) {
while ( $start < $end ) {
$temp = $nums [ $start ];
$nums [ $start ] = $nums [ $end ];
$nums [ $end ] = $temp ;
$start ++ ;
$end -- ;
}
}
}