昨天无意间看见一个慕课网网友的提问,是关于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>
代码经过本人调试可以运行得到正确结果。尽管如此,大家都知道递归的代码效率不高,限于小编水平代码比较粗糙还望大家多多指点,多多交流,相互学习,相互促进。