题目描述: : :
根据题目所给条件 :
输入 : 1 , 2 , 3 → 1 , 3 , 2
1 , 3 , 2 → 2 , 1 , 3
2 , 1 , 3 → 2 , 3 , 1
2 , 3 , 1 → 3 , 1 , 2
3 , 1 , 2 → 3 , 2 , 1
我们可以发现 , 当输入排列不是从大到小序列是 , 每个输出序列都是比输入序列大的最小值 , 所以每次只需要确定输入序列的下一次序列即可 :
假如 : 输入为 : 4 5 7 6 3 2 1 0
时间复杂度O(n^2) 空间复杂度O(1)
首先 , 从后往前遍历寻找比当前小的数值 , 即找到5的位置停止 , 然后再从后往前遍历寻找比5大的数值 ,找到6停止 , 再将5和6进行交换 , 序列变为 4 6 7 5 3 2 1 0 , 再把6之后的元素逆置 , 4 6 0 1 2 3 6 7 , 这样就得到输入序列的下一个更大的序列
时间复杂度O(n) 空间复杂度O(1)
可以先寻找上一个比当前小的数值 , 找到后交换并跳出循环 , 然后再将后边的数组逆序 , 如果没找到就直接将整个数组逆序 ,
时间复杂度为 O(2n)
代码如下 :
//取址交换函数
void swap(int *a,int *b )
{
int cur=*a;
*a=*b;
*b=cur;
}
void nextPermutation(int* nums, int n) {
if(n<=1)
return;
if(n==2){
swap(&nums[0],&nums[1]);
return;
}
for(int i=n-1;i>0;i--){
//寻找上一个比当前数小的值
if(nums[i-1]<nums[i]){
//从后往i-1寻找比i-1下标代表元素小的元素
for(int j=n-1;j>=i;j--){
//找到后将两者交换
if(nums[j]>nums[i-1]){
swap(&nums[j],&nums[i-1]);
break;
}
}
//再将从i到数组末尾进行两两交换
//注意循环边界
for(int j=0;j<(n-i)/2;j++){
swap(&nums[i+j],&nums[n-j-1]);
}
return;
}
}
//如果没有返回,证明该数组已经是最大的排序,只需要将数组逆置交换即可
//注意循环边界
for(int i=0;i<n/2;i++){
swap(&nums[i],&nums[n-i-1]);
}
return;
}