快速计算从n中任选m的所有组合
Posted in 设计
							来源: http://lifesinger.org/blog/2009/09/javascript-quick-combine/
Posted on September 25th, 2009 in 前端开发 by lifesinger
 by lifesinger
| /** | 
|  * 快速组合算法 | 
|  * 从 n 中任选 m(0 < m <= n) 个数的所有组合 | 
|  */ | 
| function quick_combine(n, m) { | 
|     var t = ((1<< n) - (1<< n - m)).toString(2), | 
|         r = [], s, p1, p2; | 
|     while((r.push(t), p1 = t.indexOf("10")) >= 0) { | 
|         s  = t.slice(0, p1); | 
|         p2 = s.indexOf("1"); | 
|         t = (p2 > 0? ((1<< p1) - (1<< p2)).toString(2) : s) | 
|              + "01"+ t.slice(p1 + 2); | 
|     } | 
|     returnr; | 
| } | 
算法思路:
假设场景为从 [a, b, c, d, e] 里, 5 选 3.
先设定第一个和最后一个组合为:
s = 1 1 1 0 0 // a,b,c
e = 0 0 1 1 1 // c,d,e
Step1. 从左到右找出第 i 个组合中的 10, 转换为 01, 并将 01 左边的 1 全部移动到最左边,得到新组合 t
Step2. 如果 t 不为 e, 继续 Step1
按照以上思路,可以得到:
1 1 1 0 0
1 1 0 1 0
1 0 1 1 0
0 1 1 1 0
1 1 0 0 1
1 0 1 0 1
0 1 1 0 1
1 0 0 1 1
0 1 0 1 1
0 0 1 1 1
共 10 种组合
网上流传的递归方案(好像是月影写的?没找到源头):
| /** | 
|  * 递归组合算法 | 
|  * 从 arr[1...n] 中任选 num(0 < num <= n) 个数的所有组合 | 
|  */ | 
| function combine(arr, num) { | 
|     var r = []; | 
|     (function f(t, a, n) { | 
|         if(n == 0) returnr.push(t); | 
|         for(var i = 0, l = a.length; i <= l - n; i++) { | 
|             f(t.concat(a[i]), a.slice(i + 1), n - 1); | 
|         } | 
|     })([], arr, num); | 
|     returnr; | 
| } | 
两种方案的性能对比: combine-test.html
在 Firefox, Chrome, Safari 浏览器中,快速组合算法优势非常明显。
在 IE 浏览器中,计算量比较小时,快速组合算法依旧有优势;但计算量大时,无优势,甚至不如递归。
2009-09-27: 修改快速组合算法,用 Math 代替 regex replace, 性能立刻提升,在所有浏览器下保持优势。