next_permutation
从邹博那里的算法:
next_permutation:
如果一个数后面有比他大的数,就应该有下一个字典序大的permutation了,下一个应当是与后面比他大的数里 最接近他的那个交换,因为这个才是紧接着他的permutation
- 找最后一个数a[i],使得后面存在比他大的数
- 找该数a[i]与后面比!!他大的数!!里最小的数a[maxmini]//一开始没想清楚,本以为1 2点两个循环可以合并,后来发现不行,必须是比a[i]大的数里找,a[i]必须循环结束了才能确定,然后maxmini 初始可以选i+1,因为至少a[i+1]>a[i]的至于是不是最小则遍历一遍打擂台即可,
我确实不太喜欢定义一个MAXNUM,总觉得这样程序适用性会有局限性,除非万不得已,例如Dijstra算法,其实也可以去掉,但是来麻烦了,而且也没有这种做法= = - swap(a[i], a[maxmini])
将该数[i]后面的数排序
void nextpermutation(int *a, int n)
{int i=n-1; while(i>=1 && a[i-1]>a[i])//property { i--; } if(i<1) return; //i-1 is to be swapped int min=a[i],mini=i; for(int j=n-1;j>=i;j--) { if(a[j]<min && a[j]>a[i-1]) { mini=j;min=a[j]; } } swap(a[i-1],a[mini]); sort(a+i,a+n);//sort [begin, end)
}
这里面有个bug,如果数字里出现重复的就挂了,因为while的目的是为了找第一次出现a[i-1]<a[i]的,=都不行的,因为等于的话,交换可能是无用交换,导致后面的还是和当前的permutation一样。因此while改为
while(i>=1 && a[i-1]>=a[i])//property
另外里面找不到这样的i的时候,允许循环pemutation需要手动调整到第一个ascending顺序的permutation,因此代码改为:
if(i<1)
{
sort(a,a+n);
return;
}
试了下库函数,next_permutation是可以直接跳过重复的permutation的,所以如果重复数的话,n!次nextpermutaion就不是到起点了,而是过头了。
另外这里面本来是 找到i=max k (a[k]b 可以确定一定后面没有比a大的数么?
答案是可以!因为前面如果能过来,说明逐个都是从后往前递减的,如果a>b 的话, 由于b>c,所以a>c 也即a只要和最右判断大小即可确定后面是否有比a大的数了!
另外还有一点性质,就是swap之后,i+1…n-1之间一定是递减的,因为a[k]是大于a[i]里最小的,a[i]比大于后面的,因为后面的肯定都小于a[i],而前面也肯定都是大于a[i],因为前面的数比a[k]大(之前是选出最小),于是我意识
到自己不了解这个性质导致性能降低,于是里面的sort全部换成reverse。。。。
但是看到邹博的代码好像挺复杂的。