leetcode-master/problems/0031.下一个排列.md

249 lines
7.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<p align="center">
<a href="https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ" target="_blank">
<img src="https://code-thinking-1253855093.file.myqcloud.com/pics/20210924105952.png" width="1000"/>
</a>
<p align="center"><strong><a href="https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p>
# 31.下一个排列
[力扣题目链接](https://leetcode-cn.com/problems/next-permutation/)
实现获取 下一个排列 的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列。
如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列)。
必须 原地 修改,只允许使用额外常数空间。
示例 1
* 输入nums = [1,2,3]
* 输出:[1,3,2]
示例 2
* 输入nums = [3,2,1]
* 输出:[1,2,3]
示例 3
* 输入nums = [1,1,5]
* 输出:[1,5,1]
示例 4
* 输入nums = [1]
* 输出:[1]
# 思路
一些同学可能手动写排列的顺序都没有写对那么写程序的话思路一定是有问题的了我这里以1234为例子把全排列都列出来。可以参考一下规律所在
```
1 2 3 4
1 2 4 3
1 3 2 4
1 3 4 2
1 4 2 3
1 4 3 2
2 1 3 4
2 1 4 3
2 3 1 4
2 3 4 1
2 4 1 3
2 4 3 1
3 1 2 4
3 1 4 2
3 2 1 4
3 2 4 1
3 4 1 2
3 4 2 1
4 1 2 3
4 1 3 2
4 2 1 3
4 2 3 1
4 3 1 2
4 3 2 1
```
如图:
以求1243为例流程如图
<img src='https://code-thinking.cdn.bcebos.com/pics/31.下一个排列.png' width=600> </img></div>
对应的C++代码如下:
```CPP
class Solution {
public:
void nextPermutation(vector<int>& nums) {
for (int i = nums.size() - 1; i >= 0; i--) {
for (int j = nums.size() - 1; j > i; j--) {
if (nums[j] > nums[i]) {
swap(nums[j], nums[i]);
sort(nums.begin() + i + 1, nums.end());
return;
}
}
}
// 到这里了说明整个数组都是倒叙了,反转一下便可
reverse(nums.begin(), nums.end());
}
};
```
# 其他语言版本
## Java
```java
class Solution {
public void nextPermutation(int[] nums) {
for (int i = nums.length - 1; i >= 0; i--) {
for (int j = nums.length - 1; j > i; j--) {
if (nums[j] > nums[i]) {
// 交换
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
// [i + 1, nums.length) 内元素升序排序
Arrays.sort(nums, i + 1, nums.length);
return;
}
}
}
Arrays.sort(nums); // 不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列)。
}
}
```
## Python
>直接使用sorted()不符合题意
```python
class Solution:
def nextPermutation(self, nums: List[int]) -> None:
"""
Do not return anything, modify nums in-place instead.
"""
for i in range(len(nums)-1, -1, -1):
for j in range(len(nums)-1, i, -1):
if nums[j] > nums[i]:
nums[j], nums[i] = nums[i], nums[j]
nums[i+1:len(nums)] = sorted(nums[i+1:len(nums)])
return
nums.sort()
```
>另一种思路
```python
class Solution:
'''
抛砖引玉因题目要求“必须原地修改只允许使用额外常数空间”python内置sorted函数以及数组切片+sort()无法使用。
故选择另一种算法暂且提供一种python思路
'''
def nextPermutation(self, nums: List[int]) -> None:
"""
Do not return anything, modify nums in-place instead.
"""
length = len(nums)
for i in range(length-1, 0, -1):
if nums[i-1] < nums[i]:
for j in range(length-1, 0, -1):
if nums[j] > nums[i-1]:
nums[i-1], nums[j] = nums[j], nums[i-1]
break
self.reverse(nums, i, length-1)
break
else:
# 若正常结束循环,则对原数组直接翻转
self.reverse(nums, 0, length-1)
def reverse(self, nums: List[int], low: int, high: int) -> None:
while low < high:
nums[low], nums[high] = nums[high], nums[low]
low += 1
high -= 1
```
>上一版本简化版
'''python
class Solution(object):
def nextPermutation(self, nums: List[int]) -> None:
n = len(nums)
i = n-2
while i >= 0 and nums[i] >= nums[i+1]:
i -= 1
if i > -1: // i==-1,不存在下一个更大的排列
j = n-1
while j >= 0 and nums[j] <= nums[i]:
j -= 1
nums[i], nums[j] = nums[j], nums[i]
start, end = i+1, n-1
while start < end:
nums[start], nums[end] = nums[end], nums[start]
start += 1
end -= 1
return nums
'''
## Go
```go
```
## JavaScript
```js
//卡尔的解法(吐槽一下JavaScript的sort和其他语言的不太一样只想到了拷贝数组去排序再替换原数组来实现nums的[i + 1, nums.length)升序排序)
var nextPermutation = function(nums) {
for(let i = nums.length - 1; i >= 0; i--){
for(let j = nums.length - 1; j > i; j--){
if(nums[j] > nums[i]){
[nums[j],nums[i]] = [nums[i],nums[j]]; // 交换
// 深拷贝[i + 1, nums.length)部分到新数组arr
let arr = nums.slice(i+1);
// arr升序排序
arr.sort((a,b) => a - b);
// arr替换nums的[i + 1, nums.length)部分
nums.splice(i+1,nums.length - i, ...arr);
return;
}
}
}
nums.sort((a,b) => a - b); // 不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列)。
};
//另一种
var nextPermutation = function(nums) {
let i = nums.length - 2;
// 从右往左遍历拿到第一个左边小于右边的 i,此时 i 右边的数组是从右往左递增的
while (i >= 0 && nums[i] >= nums[i+1]){
i--;
}
if (i >= 0){
let j = nums.length - 1;
// 从右往左遍历拿到第一个大于nums[i]的数,因为之前nums[i]是第一个小于他右边的数,所以他的右边一定有大于他的数
while (j >= 0 && nums[j] <= nums[i]){
j--;
}
// 交换两个数
[nums[j], nums[i]] = [nums[i], nums[j]];
}
// 对 i 右边的数进行交换
// 因为 i 右边的数原来是从右往左递增的,把一个较小的值交换过来之后,仍然维持单调递增特性
// 此时头尾交换并向中间逼近就能获得 i 右边序列的最小值
let l = i + 1;
let r = nums.length - 1;
while (l < r){
[nums[l], nums[r]] = [nums[r], nums[l]];
l++;
r--;
}
};
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>