递归是一个方法调用方法自己本身去解决问题,这是个比较神奇也实用的功能。本篇是为了解决《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