下一个排列
其实,我们完全没有必要去背诵: next_permutation在干嘛
我们需要知道,什么叫做: “下一个排列”
s = "123" 他的所有全排列ALL: 123, 132, 213, 231, 321, 312
所谓“下一个排列”: 即给定某个排列(比如“213”),求他在ALL里的下一个排列(即231)
即,下一个排列 他从某种10进制数字的角度去看,也就是数值增大的过程
' 全排列ALL的个数,不一定等于n! 如果没有重复元素,确实是n! '
' 但如果有重复数字, 比如(122333) 那他的全排列有:6! / 2! / 3! 个 '
我们需要2个问题:
1, next_permutation是怎么实现的
2, 他是时间复杂度
next_permutation实现原理
cur = xxxx 4 6 5 5 4 4 3 2
i j
他的下一个排列nex是: xxxx 5 2 3 4 4 4 5 6
1, 从后往前找,找“第一个”满足: A[i] < A[i + 1]的点,即图中[i]的位置
(nex[i]一定放的是>4的数!! 因为,i后面 已经是递减达到饱和了 )
2, “再次”从后往前找, 第一个 > A[i]=4 的位置 即[j]
swap(A[i], A[j])
3, 此时变成: xxxx 5 6 5 4 4 4 3 2
i
然后执行: reverse( A.begin() + i + 1, A.end() );
最后的nex = xxxx 5 2 3 4 4 4 5 6
bool Next_permutation(vector<int>& A){
int n = A.size();
for(int i = n - 2; i >= 0; --i){
if(A[i] < A[i + 1]){
' 一旦这个if成立, 下面的 return true一定会执行!!'
' 意味着: 这个算法的时间是: O(n)的!!! '
for(int j = n - 1; ; --j){
if(A[j] > A[i]){
' 一定会找到 '
swap(A[i], A[j]);
reverse(A.begin() + i + 1, A.end());
return true;
}
}
}
}
return false; ' 说明,A已经达到饱和,比如: 4 4 3 3 2 2 '
}
' 他的时间为: [8 9 8 8 8 ... ] '
' n + n + (reverse=n) = 3n, 即O(n)的时间!!! '
' 这个时间的分析, 非常非常容易出错!!! '
' 因为有2层的O(n)的循环,你很容易会认为: 是O(n^2)的时间 !! '
' 对时间分析的出错, 会导致 非常严重的后果!!! '
'因为我们: 第一次for循环,是有个一个if判断的!! '
'一旦if成立,第二次的for循环里的if 也必然会成立!! 导致,时间其实是O(n+n)的!!'
next_permutation时间分析
假如从[1,2,3...,n]无限执行下一个排列, 那么 此时的时间,肯定是和他的全排列个数是相关的
他有n!的排列, 那么时间 至少是n!量级的,这还不算我们的next算法的时间
这个时间比较复杂, 平时也基本不会用到
但,假如给定你一个K,让你求cur的下K个排列 是什么? (保证,下K个排列一定存在,不会溢出)
' 这个问题,你肯定会思考一会.... 但其实,没有什么简易的方法,就是暴力 '
即: while(k --){
Next_permutation(A); }
关键是,我们要分析时间!!
K * (n) = k*n ' 千万千万不要把next_permutation,分析成n^2的时间!! '
两个全排列间的转换
问题: 给定两个全排列(即各个数字出现的次数相同)比如beg=[1<