本帖最后由 xdsnet 于 2018-04-11 11:20 编辑
如果已经去重,且知道行数,其实有一个很取巧的方法可以很快的得出结果,而且有重复的甚至比没有重复的更快。 这需要用到一个数学知识了 假设有N行(相互不重复,对应0,1,2,...,N-1 的序号),则取M个,每行可以重复时,就是有N*N..N(M个N相乘),所以如果有M段数字Z,每段有K种可能(K>=N),则这个整体的0到Z的最大值 间的各个数字可以映射为取值可能,因为K可以用二进制表示,所以可以转换为K(n),其中n是K对应的二进制位数,所以内容转换为有nM位的二进制数,可以分成M段,每段有n位,其对应的符合条件的数k(k<=N)就是符合条件的行序号。 这样依次增加输出数字(判断分段数值是否符合范围),就可以查出对应的重复行的可能,增加条件保证每段不重复就可以输出 不重复的可能。
这个算法的优点是O(n)复杂度的了。
不过这个算法实现可能需要用到大整数 位运算,不知道你好不好实现。 比如,有8行,要取3行,因为N=8,对应n=3,M=3,所以需要一个9位二进制数表示可能(重复时刚好全覆盖) - // 伪C语言 逻辑实现
- for(i=0;i<1024;i++){
- line1= (i>>(3*0)) & 0x7;
- line2= (i>>(3*1)) & 0x7;
- line3= (i>>(3*2)) & 0x7;
- // 如果扩展,这里line等可能需要用数组存储, 1024要换成n*M+1位二进制数, 0x7要换成对应n的n位1二进制数,3换成n对应数字,0,1,2等其实是和M相关的,后面就可以用到循环中
- // 例如 for(j=0;j<M;j++){
- // line[j]=(i>>(3*j)) & 0x7;
- // }
- // 这里根据 line1,line2,line3 输出可重复的结果
- if(line1==line2 || line1== line3 || line2==line3){ // 这里过滤重复情况
- continue
- }
- // 这里根据 line1,line2,line3 输出不重复的结果
- }
复制代码
|