每日算法之二十七:Next Permutation(下一个字典序)

时间:2021-10-01 23:20:53

求解的是下一个字典序,下面给出两个不同理解方式的字典序的定义:可以直接看第二种定义,但是算法还是用官方的定义来求解。

1)官方定义:字典序法是由当前序列直接生成下一个排列的算法:排列定义:P = P1P2```Pn

    第一步:求满足关系式P(k-1)<P(k)的k的最大值,设为i,即 

i = max{k|P(k-1)<P(k)}

    第二步:求满足关系式P(i-1)<P(k)的k的最大值,设为j,即

j = max{k|P(i-1)<P(k)}

    第三步:P(i-1)与P(j)互换。

    第四步:把序列中P(i)P(i+1)```P(n)顺序逆转。

  举例:对于3421,可知i = 2,j = 2 。P(1)与P(2)交换得4321,再将321逆转可得下一个排列4123

2)理解式的定义:以上面为例,3421,后三位421已经是完全逆序的,因此以3开头的已经全部结束,接下来是以4开头的,并且后三位是顺序的,因此事4123.再说一个例子,4312,后两位是顺序的,下一个字典序应把两个转为逆序即可。对2341来说,后两位是逆序的,说明以23开头的结束了,接下来是以24开头的,且后面是顺序的。

下面是1234的所有字典序,多看一下前后关系会明白的。

1234->1243->1324->1342->1423->1432->2134->2143->2314->2341->2413->2431->3124->3142->3214->3241->3412->3421->4123->4132->4213->4231->4312->4321

下面是代码:

class Solution {
public:
void swaptwoiterator(vector<int>::iterator begin,vector<int>::iterator end)
{//交换两个迭代器指向的值,要自己写
int temp = *begin;
*begin = *end;
*end = temp;
}
void reverse(vector<int>::iterator begin,vector<int>::iterator end)
{//反转区间上的值
size_t len = end - begin;
for(size_t i = 0;i<len/2;i++)
swaptwoiterator(begin+i,end-i-1);
}
void nextPermutation(vector<int> &num) {

size_t len = num.size();
if(len<=1)
return;
size_t i = len - 1;
while(i>0)//找到i的位置
{
if(num[i-1]<num[i])
break;
i--;
}
if(i == 0)//已经完全逆序,反转后输出
{
reverse(num.begin(),num.end());
return;
}
size_t j = len - 1;
while(num[j]<=num[i-1])//找到j的位置
j--;
swap(num[i-1],num[j]);
reverse(num.begin()+i,num.end());
}
};