题目
求全排列中某一个排列的下一个排列
Implement next permutation, which rearranges numbers into the lexicographically next greater permutation of numbers.
If such arrangement is not possible, it must rearrange it as the lowest possible order (ie, sorted in ascending order).
The replacement must be in-place, do not allocate extra memory.
Here are some examples. Inputs are in the left-hand column and its corresponding outputs are in the right-hand column.
1,2,3
→ 1,3,2
3,2,1
→ 1,2,3
1,1,5
→ 1,5,1
思路
对于没有元素重复的情况:
(1)从右往左,找到第一个可以逆序的逆序对,例如 2 1 4 3 第一个逆序对是 1<3 , 2 4 3 1 第一个逆序对是 1<2 ;
(2)若找到的逆序对下标是 num[ i ]<num[ j ] ,交换两者的值;
(3)翻转 num 中 i+1~end 的数据,即为结果。
class Solution {
public:
void nextPermutation(vector<int> &num) {
// Start typing your C/C++ solution below
// DO NOT write int main() function
int i=num.size()-1;
int j=num.size()-1;
bool flag = false; //if have the reverse-pair;
for(i=num.size()-1;i>0;i--)
{
for(j=i-1;j>=0;j--)
if(num[j]<num[i])
{
flag = true;
break;
}
if(flag)
break;
}
if(j>=0)
{
int tmp = num[i];
num[i] = num[j];
num[j] = tmp;
}
reverse(num.begin()+j+1,num.end());
}
};
上述代码小数据可以通过。再简化一下:
class Solution {
public:
void nextPermutation(vector<int> &num) {
// Start typing your C/C++ solution below
// DO NOT write int main() function
for(int i=num.size()-1;i>0;i--)
{
for(int j=i-1;j>=0;j--)
if(num[j]<num[i])
{
int tmp = num[i];
num[i] = num[j];
num[j] = tmp;
reverse(num.begin()+j+1,num.end());
return ;
}
}
reverse(num.begin(),num.end());
return ;
}
};
如果存在重复的情况,上述代码存在一个问题:
例如 对于一个 数列 4 1 2 3 2 ,正确的逆序对是 2<3 ,而上述找到的是1<2 ,所以找到的不是一个理想的逆序对。
时间复杂度是O(N2),更正之后的代码:
class Solution {
public:
void nextPermutation(vector<int> &num) {
// Start typing your C/C++ solution below
// DO NOT write int main() function
for(int i=num.size()-2;i>=0;i--)
{
for(int j=num.size()-1;j>i;j--)
if(num[i]<num[j])
{
int tmp = num[i];
num[i] = num[j];
num[j] = tmp;
reverse(num.begin()+i+1,num.end());
return ;
}
}
reverse(num.begin(),num.end());
return ;
}
};
当然上述还可以进一步简化至时间复杂度 O(N)
class Solution {
public:
void nextPermutation(vector<int> &num) {
// Start typing your C/C++ solution below
// DO NOT write int main() function
int i=0;
for(i=num.size()-2;i>=0;i--)
{
if(num[i]<num[i+1])
break ;
}
for(int j=num.size()-1;j>i;j--)
{
if(num[i]<num[j])
{
int tmp = num[i];
num[i] = num[j];
num[j] = tmp;
reverse(num.begin()+i+1,num.end());
return ;
}
}
reverse(num.begin(),num.end());
return ;
}
};
最新 java
public class Solution {
public void nextPermutation(int[] num) {
//1.找到最后一个升序位置pos
int pos = -1;
for (int i = num.length - 1; i > 0; i--) {
if (num[i] > num[i - 1]) {
pos = i - 1;
break;
}
}
//2.如果不存在升序,即这个数是最大的,那么反排这个数组
if (pos < 0) {
reverse(num, 0, num.length - 1);
return;
}
//3.存在升序,那么找到pos之后最后一个比它大的位置
for (int i = num.length - 1; i > pos; i--) {
if (num[i] > num[pos]) {
int tmp = num[i];
num[i] = num[pos];
num[pos] = tmp;
break;
}
}
//4.反排pos之后的数
reverse(num, pos + 1, num.length - 1);
}
public void reverse(int[] num, int begin, int end) {
int l = begin, r = end;
while (l < r) {
int tmp = num[l];
num[l] = num[r];
num[r] = tmp;
l++;
r--;
}
}
}