您的位置:首页 > 其它

求1~19整数中,求出和为20的组合

2015-10-27 07:15 405 查看
之前去公司面试,其中有一道问题是如何在1~19中,和为20的组合有多少个?(注意:数字不重复跟不颠倒。例如:1+1+1.....=20,19+1和1+19是一样的)。

我的思路比较简单,纯粹利用三重循环来求出组合。显然我就是算法薄弱的人(效率太低了),现在想想算法真的很重要。另外,下面贴的代码是从网上摘下来的(利用递归思想),我看了几天才看懂,没办法有点笨。不嫌弃的话继续看我分析,如有不当之处,请指出。废话少说,先贴出代码再分析。

public class Test

{

static int array[]; // 定义一个数组,用来保存带排序的数字(1~19)

static int count; //这是我测试加的,来测试 函数执行 的次数(大家可以不管)

static int num; //这是我测试加的,来测试 等于20的组合 有多少(大家可以不管)

static //静态初始化块,即new一个Test类,就会自动执行static里面的内容(只执行一次)

{

array = new int[19];

for (int i = 1; i <= 19; i++)

{

array[i - 1] = i;

}

}

//核心方法

//tmp[]是临时数组,arrayIndex,tmpIndex分别是2个数组的索引

static void combination(int array[], int tmp[], int arrayIndex, int tmpIndex)

{

count++;//统计函数调用的次数

if (tmpIndex == array.length)

{

return;

}

for (int i = arrayIndex; i < array.length; i++)//arrayIndex,tempIndex参数的初始值为0

{

tmp[tmpIndex] = array[i];

int result = 0;

for (int z = 0; z <= tmpIndex; z++)

{

result += tmp[z];

}

if (result == 20)

{ num++;

for (int j = 0; j <= tmpIndex; j++)

{

System.out.print(tmp[j] + "+");

}

System.out.println("=20");

return; //优化效果部分(等于20后不用试后面的数字)

}

else if (result > 20)

{

return;

}

combination(array, tmp, i + 1, tmpIndex + 1);//递归调用

}

}

public static void main(String[] args)

{

combination(array, new int[19], 0, 0);

System.out.println("count------"+count);

System.out.println("num------"+num);

}

}

执行结果

1+2+3+4+10+=20

1+2+3+5+9+=20

1+2+3+6+8+=20

1+2+3+14+=20

1+2+4+5+8+=20

1+2+4+6+7+=20

1+2+4+13+=20

1+2+5+12+=20

1+2+6+11+=20

1+2+7+10+=20

1+2+8+9+=20

1+2+17+=20

1+3+4+5+7+=20

1+3+4+12+=20

1+3+5+11+=20

1+3+6+10+=20

1+3+7+9+=20

1+3+16+=20

1+4+5+10+=20

1+4+6+9+=20

1+4+7+8+=20

1+4+15+=20

1+5+6+8+=20

1+5+14+=20

1+6+13+=20

1+7+12+=20

1+8+11+=20

1+9+10+=20

1+19+=20

2+3+4+5+6+=20

2+3+4+11+=20

2+3+5+10+=20

2+3+6+9+=20

2+3+7+8+=20

2+3+15+=20

2+4+5+9+=20

2+4+6+8+=20

2+4+14+=20

2+5+6+7+=20

2+5+13+=20

2+6+12+=20

2+7+11+=20

2+8+10+=20

2+18+=20

3+4+5+8+=20

3+4+6+7+=20

3+4+13+=20

3+5+12+=20

3+6+11+=20

3+7+10+=20

3+8+9+=20

3+17+=20

4+5+11+=20

4+6+10+=20

4+7+9+=20

4+16+=20

5+6+9+=20

5+7+8+=20

5+15+=20

6+14+=20

7+13+=20

8+12+=20

9+11+=20

可能大家还是不太明白是怎么一回事吧?递归理解好了问题就解决了!

首先,大家先不用急,给你们看个下例子 再去理解上面的题目就好多了。

现在有个这样的情况:

public class Test1 {

static int count = 0;

static void show(){

for(int i=1;i<=10;i++){

count++;

if(count>1){System.out.println("count的值为:"+count);return;}

show();

System.out.println("LOL I love!");

}

}

public static void main(String[] args) {

show();

}

}

问控制台会输出什么?

输出的结果为:

count的值为:2

LOL I love!

count的值为:3

为什么会这样呢?大家跟我来分析流程。1.程序首先进入main方法调用show().
2.count的初始值为0,第一次show()方法中count变为了1->程序执行if下面的show()方法(此时暂时不会执行show下面的输出语句)。程序重新执行show方法,因为count是全局变量,因此 此时的count变为2(大家请注意 for循环里面的 i 的值并未 为2,还是从1开始。因为递归的各个局部变量是保存在堆栈里面的)。3.此时的count>1输出 count的值为:2,return后此次递归结束,返回结果给上一层。此时继续执行步骤2中中断的路程(也就是show下面的输出语句).此时输出 LOL
I love!(大家注意count是全局变量,现在仍未2 )因为此时的i=1,因此会在执行一次循环,输出结果为 count的值为:3

比较简洁的描述为:

1.count = 0 ,show()开始执行,count = 1。

2.递归调用show() ,count = 2,输出 count的值为:2,此时 i=1。

3.第二个show()执行遇到结束条件 return;返回上一层的状态

4.执行第一次show下面的输出方法 输出 LOL I love!

5.第一层状态的 i 也为1(<10),count = 3 ,输出 count的值为:3,递归结束(此时不会执行下面的show方法了,因为递归是先从上往下调用,然后从下往上返回结果,重新返回到第一层状态时候递归就结束了,这点大家可能不是很好理解。)

因此,了解了递归,就可以轻松了解1~19中组成20数字的递归解法了。程序运行是这样的顺序

1.arrayIndex初始值为0 array[arrayIndex]=1<20

2..arrayIndex++
array[0~arrayIndex]=1+23<20 .......arrayIndex
= 5 array[0~5]=1+2+3+4+5+6=22>20 此时一共调用了6层方法,因为22>20,所以第六层递归满足结束的条件。于是第五个加数就不存在了,第四个加数加1(没掉一层combination方法,加数就增加一个).以此类推

3.展示第一个结果
①.1+2+3+4+5+6=22>20--->②.1+2+3+4+6=21>20----->③.1+2+3+4+7<20......1+2+3+4+10=20.第四层递归结束
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: