javascript实现组合的递归算法及变种
实现某数组的组合算法有很多种,其中以递归为最多,而且网上不乏高效率的示例,这里只演示一种实现方式.
代码
1 /**
2 * 递归组合
3 * 从 arr[1n] 中任选 num(0 < num <= n) 个数的所有组合
4 */
5 function combine(arr, num) {
6 var r = [];
7 (function f(t, a, n) {
8 if (n == 0) return r.push(t);
9 for (var i = 0, l = a.length; i <= l - n; i++) {
10 f(t.concat(a[i]), a.slice(i + 1), n - 1);
11 }
12 })([], arr, num);
13 return r;
14 }
15
16 /** 测试代码 **/
17 combine([1,2,3,4,5,6,7,8,9], 3);
2 * 递归组合
3 * 从 arr[1n] 中任选 num(0 < num <= n) 个数的所有组合
4 */
5 function combine(arr, num) {
6 var r = [];
7 (function f(t, a, n) {
8 if (n == 0) return r.push(t);
9 for (var i = 0, l = a.length; i <= l - n; i++) {
10 f(t.concat(a[i]), a.slice(i + 1), n - 1);
11 }
12 })([], arr, num);
13 return r;
14 }
15
16 /** 测试代码 **/
17 combine([1,2,3,4,5,6,7,8,9], 3);
然而,事情并不是都这么简单,现在遇到一个新问题,我定义了一个新的数组
var arr = [[1,2,3],
[1,2,3,4,5],
[2,4,6,8],
[3,5,7,9]];
要求是从数组arr的每个元素中任意取一个值出来,组成一个长度为4(即arr.length)的组合,求有多少种组合方式.这个时候,如果想要再次利用上面的递归,就需要改造一下了.主要变化就是在每次传入匿名函数的参数上,以保证每次要循环的数组是arr的下一个元素而不是当前元素本身.
代码
1 function combine_ex(arr) {
2 var r = [];
3 (function f(t, a, n) {
4 if (n == 0) return r.push(t);
5 for (var i = 0; i < a[n-1].length; i++) {
6 f(t.concat(a[n-1][i]), a, n - 1);
7 }
8 })([], arr, arr.length);
9 return r;
10 }
2 var r = [];
3 (function f(t, a, n) {
4 if (n == 0) return r.push(t);
5 for (var i = 0; i < a[n-1].length; i++) {
6 f(t.concat(a[n-1][i]), a, n - 1);
7 }
8 })([], arr, arr.length);
9 return r;
10 }
接着就有新问题了,如果要对上面变长的二维数组,要求是从数组arr的每个元素中任意取一个值出来,组成一个长度为指定任意值的组合怎么办?要说办法也就在这里了,无非就是将前面两种函数一起使用,先求出最长组合的集合,然后对每一个元素求指定长度的组合.
总归,组合算法的需求是多样的,不管怎么变,都能从最基本的算法进行衍变,派生出复合的算法出来.