目录
题目描述:
实现获取下一个排列的函数,算法需要将给定数字序列重新排列成字典序中下一个更大的排列。
如果不存在下一个更大的排列,则将数字重新排列成最小的排列(即升序排列)。
必须原地修改,只允许使用额外常数空间。
以下是一些例子,输入位于左侧列,其相应输出位于右侧列。1,2,3
→ 1,3,2
3,2,1
→ 1,2,3
1,1,5
→ 1,5,1
解题思路:
参考思路:网上看来一个示例,觉得挺好的,也没必要另外找一个了。
6 5 4 8 7 5 1
从排列的后面开始看,想这个排列的下一个排列是怎样的。(1)1和5调换了没有用。
(2)7、5和1调换了也没有效果,因此而发现了8、7、5、1是递减的。
(3)如果想要找到下一个排列,找到递增的位置是关键。因为在这里才可以使其增长得更大。
(4)于是找到了4,然后在后面找出比4大但在这些大数里面最小的值,并将其两者调换。
那么整个排列就成了:6 5 5 8 7 4 1
(5)然而最后一步将后面的8 7 4 1做一个递增排序。
(6)得到6 5 5 1 4 7 8
(1)由后往前找到递增开始的位置,比如该位置是index-1,数字是4;
(2)找到大于4的数字,且该数字是后面最小的那个。因为后面是逆序的,所以第一个大于4的数字就是要找的,4的索引是index-1;
(3)再将后面的数即index后面从小到大排序。
C++代码:
执行用时:0 ms, 在所有 C++ 提交中击败了100.00%的用户
内存消耗:11.8 MB, 在所有 C++ 提交中击败了48.48%的用户
通过测试用例:265 / 265
class Solution {
public:
void nextPermutation(vector<int> &num) {
// 1 由后往前找到递增开始的位置,比如该数字是4
int index = num.size() - 1;
while (index > 0 && num[index - 1] >= num[index]){ // 逆序则继续
index--;
}
if (index == 0){ // 整个数组都是逆序的
sort(num.begin(), num.end());
return;
}
// 2 找到大于4的数字,且该数字是后面最小的那个。
// 因为后面是逆序的,所以第一个大于4的数字就是要找的,4的索引是index-1
for (int i = num.size() - 1; i >= index; i--){
if (num[i] > num[index - 1]){ // 找到,则跳出循环
swap(num[i], num[index - 1]);
break;
}
}
// 3 再将后面的数即index后面从小到大排序
sort(num.begin() + index, num.end());
return;
}
};
python
执行用时:32 ms, 在所有 Python 提交中击败了7.24%的用户
内存消耗:12.8 MB, 在所有 Python 提交中击败了98.29%的用户
通过测试用例:265 / 265
class Solution(object):
def nextPermutation(self, nums):
"""
:type nums: List[int]
:rtype: None Do not return anything, modify nums in-place instead.
"""
# 1 从后往前找,递增开始的位置
idx = len(nums)-1
while idx > 0:
if nums[idx-1] < nums[idx]: # 如果递增,则跳出循环,此时递增开始的位置是idx-1
break
else:
idx -= 1
# 2 如果全部逆序,则返回升序排列,list原地排序
if idx == 0: # [1]
nums.sort()
return nums
# 3 找到后面大于且最接近nums[idx-1]的数字,进行交换
# 因为是后面是逆序的,所以第一个大于的即是最接近
for i in range(len(nums)-1, idx-1, -1):
if nums[i] > nums[idx-1]: # 找到了,交换,跳出循环
tmp = nums[i]
nums[i] = nums[idx-1]
nums[idx-1] = tmp
break
# 4 将idx-1后面的数字升序排列
i = idx
j = len(nums)-1
while i < j:
tmp = nums[i]
nums[i] = nums[j]
nums[j] = tmp
i += 1
j -= 1
return nums