递归是一个方法调用方法自己本身去解决问题,这是个比较神奇也实用的功能。本篇是为了解决《Java数据结构和算法》一书第六章递归中,最后留下的“三个有趣的问题”。
题一:求一个数的乘方
便携计算器中能够求一个数的乘方,通常是X^Y,表示求X的Y次方。但是如果没有这个键又改如何求捏?
解析:这是三个题目中最简单的,用递归求一个的乘方。代码如下:
package test.recursion; public class PowerQ { public int power(int x,int y) throws Exception { int result = 0; if(y < 0) throw new Exception("y不能小于0"); else if(y == 0){//当y=0时,结果为1; result = 1; } else if(y/2 == 1)//当y/2时,就计算X*X; result = x*x; else //其他就递归 result = power(x,y/2)*power(x,y/2); if(y%2 == 1)//当y除以2余数为1时,多乘一个X; result = result*x; return result; } public static void main(String[] args) throws Exception { PowerQ pq = new PowerQ(); System.out.println(pq.power(10, 0)); System.out.println(pq.power(10, 1)); System.out.println(pq.power(10, 2)); System.out.println(pq.power(10, 3)); System.out.println(pq.power(10, 4)); System.out.println(pq.power(10, 5)); } }结果如下:
1 10 100 1000 10000 100000
题二:背包问题
背包问题是计算机科学里的经典问题。在最简单的形式中,包括试图将不同重量的数据项放到背包中,以使背包最后达到指定的总重量。不需要把所有的选项都放入背包中。假如一个背包最多能放20斤东西,现在有五个数据项可以用,分别是11斤、8斤、7斤、6斤、5斤。如何能正好达到20斤捏?
解析:需要正好达到20斤,没有数据项数目的要求。只能一个个的去遍历。代码如下:
package test.recursion; import java.util.ArrayList; public class BackpackQ { public int[] numbs; public ArrayList<Integer> adaptNumbs; public BackpackQ(int[] numbs) { this.numbs = numbs; adaptNumbs = new ArrayList<Integer>(); } public boolean adapt(int start,int max) { boolean flag = false; for (int i = start; i < numbs.length; i++) { int temp = max - numbs[i]; if(temp == 0) flag = true; else if(temp < 0) flag = false; else flag = adapt(i+1,temp); if(flag) { adaptNumbs.add(numbs[i]); return true; } } return flag; } public static void main(String[] args) { int[] numbs = {11,8,7,6,5}; BackpackQ bq = new BackpackQ(numbs); boolean adapt = bq.adapt(0, 20); System.out.println(bq.adaptNumbs.toString()+ adapt); } }结果如下:
[5, 7, 8]
题三:选择一支队
在数学中,组合是对事物的一种选择,而不是考虑它们的顺序。例如:有5个登山队员,分别为ABCDE。要从五人中选三个人组成先头部队,需要列出所有可能的组合。
解析:大学中学过组合的知识,知道假如用(n,k)表示n个中选K个,那就有表达式:
(n,k)=(n-1,k-1)+(n-1,k)
那么5选3就可以变为 (5,3)=(4,2)+(4,3)然后继续递归每个子项,直到n个中选1个和n个中选n个为止。代码如下:
package test.recursion; import java.util.HashSet; import java.util.Set; public class TeamQ { public String[] items; //原始数据项 public Set<String> rs; //set 可以防止出现重复项 public TeamQ(String[] items,int k){ this.items = items; String temp=""; rs = new HashSet<String>(); seek(items.length,k,temp); //开始调用递归方法 } public void seek(int n,int k,String temp){ if(k>1)// 当k>1时,(n-1,k-1) seek(n-1,k-1,temp+items[items.length-n]); if(n>k)// 当 n>k时,(n-1,k) seek(n-1,k,temp); if(k == 1){ //当k==1,即n中选1个,遍历剩下的数据项,每个结果添加到结果set中 for (int i = items.length- n ; i < items.length; i++) { String tempIn = temp +items[i]; rs.add(tempIn); } } if(k == n && k != 1){//当k==n且k!=1,即n中选n个,则将所有数据项一次性遍历,结果添加到结果set中 String tempIn = temp; for (int i = items.length- n ; i < items.length; i++) { tempIn = tempIn +items[i]; } rs.add(tempIn); } } public static void main(String[] args) { String[] sa = {"A","B","C","D","E"}; TeamQ tq = new TeamQ(sa, 3); StringBuffer sb = new StringBuffer("数据项:"); boolean isFirst = true; for (String str : sa) { if(!isFirst){ sb.append(","); } sb.append(str); isFirst = false; } sb.append("\n中"+sa.length+"选"+3+"\n结果为:"); isFirst = true; for (String str : tq.rs) { if(!isFirst){ sb.append(","); } sb.append(str); isFirst = false; } System.out.println(sb.toString()); } }结果如下:
数据项:A,B,C,D,E 中5选3 结果为:BCD,ABD,ABC,ACE,ACD,BDE,BCE,ABE,ADE,CDE