手记

关于N个中选M个组合问题的递归算法(JavaScript版)

昨天无意间看见一个慕课网网友的提问,是关于8个里面选5个的组合问题,引起了小编的兴趣。起初小编感觉问题比较容易,便不假思索的堆起代码。后来调试发现,小编入坑了。经过一番分析最终还是解决了这个比较经典的问题。限于小编水平,只是采用了比较容易理解的递归算法解决该问题。
言归正传,N个中选M个组合问题(其中:N>=M),可以分解为两个小规模问题:
1.从N个中选取编号最小的一个,然后从剩余的N-1个中选取M-1个;
2.从除最小编号外剩余的N-1个中选出M个;
经过递归便可得到所求解。(即:C(M,N) = C(M-1,N-1) + C(M,N-1))
看上去问题比较清晰,但是,递归的关键还是问题的终止条件:
1.当问题规模变化成从M中选去M个的时候即(N=M),选取工作完成;
2.当选取的M=0时,即已经选择了M个时,选取工作完成。
代码如下:

<script type="text/javascript">
var list1 = [1,2,3,4,5,6,7,8]; //初始集合数组即选集
/*在数组中移除指定下标的元素,并返回移除后的新数组*/
function removeByIndex(list,index){
    var list2 = new Array();
    for(var i=0;i<list.length;i++){
        if(index!=i){
            list2.push(list[i]);
        }
    }
    return list2;
}

/*组合问求解递归函数
 * n,m为从n个中选取m个(n>m)
 * list为待选取的集合数组
 * s为所选取的m个元素的数组
 */
function combine(n,m,list,s){
    if(m==0){
        document.write(s+"<br>");
    }
    else if(m==n){
        //倒序记录选取的元素
        s[m-1] = list[0]; 
        if(n!=1){
            for(var i=0;i<m;i++){
                s[m-i-1] = list[i]
            }
        }
        document.write(s+"<br>")    
    }
    else{
        var list2 = new Array();//用于存放选取元素后剩余的选集
        list2 = removeByIndex(list,0);
        combine(n-1,m,list2,s);//除去最小编号后从n-1个元素中选取m个
        s[m-1] = list[0];//选取最小编号元素
        combine(n-1,m-1,list2,s); //除去最小编号后从n-1个元素中选取m-1个

    }
}

var s = new Array();
combine(8,5,list1,s);
</script>

代码经过本人调试可以运行得到正确结果。尽管如此,大家都知道递归的代码效率不高,限于小编水平代码比较粗糙还望大家多多指点,多多交流,相互学习,相互促进。

1人推荐
随时随地看视频
慕课网APP