《组合数学》中的许多问题都可以通过计算机给出模拟(而不是通过数学公式推出),一般是利用了计算机速度优势进行大量的枚举。
许多解法中都引入“递归”算法,使得表述更加简捷。
示例:上台阶问题
n阶台阶,如果第一次上一阶台阶,则有f(n-1)种情况,第一次上二阶台阶,则有f(n-2)种情况
每个父问题都有子问题确定,递归的出口是n == 1, n == 2,此为最简单情况
代码如下:
package NO4;
public class Test25 {
static int f(int n){
if(n == 1) return 1;
if(n == 2) return 2;
return f(n - 1) + f(n - 2);
}
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println(f(10));
}
}
当n的数目较小时候,程序运行耗时还可以
当n的数目较大的时候,递归会递的比较深入,耗时比较严重
如
f(5)
---> f(4)
--->f(3)
--->f(2)
--->f(1)
---->f(2)
---->f(3)
--->f(2)
--->f(1)
如上所示:递归中存在重复计算的过程,所以当n的数目较大的时候,耗时严重,此时应考虑优化
package NO4;
import java.util.*;
public class Test26 {
static Map map = new HashMap();
static int f(int n){
if(map.get(n)!=null) return(Integer)map.get(n);
int x = f(n-1) + f(n-2);
map.put(n, x);
return x;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
map.put(1, 1);
map.put(2, 2);
System.out.println(f(45));
}
}
以上优化做的工作是,把一个值计算完成后,即保存下来,避免重复计算
利用了java中的HashMap
HashMap是一种键值对的集合,表现形式为key=value,其中key是唯一的,value可以重复,如果在开发中用到需要这种表现形式的话可以用HashMap
程序一直往下递,一直递到n == 1 , n == 2的情况,然后开始归,比如f(3) = f(2) + f(1),然后把f(3)的值保存起来,
求f(4) = f(3) + f(2)时候,则直接调用Map存的值即可,避免重复计算
f(n) f(n-1) f(n-2) f(n-3) f(n-4) f(4) f(3) f(2)
f(n-5) f(2) f(1)
f(n-4)
f(n-3)
f(n-2) f(n-3)
f(n-4)
f(n) f(n-1) f(n-2) f(n-3) f(4) f(3) f(2) f(1)
如上所示:f(45)会一直计算f(n-1) 即 f(44) f(43) f(42)--->f(3)->f(2) f(1),然后再回调给父问题
如f(3) = f(2) + f(1)
f(4) = f(3) + f(2)
f(5) =(f4)+f(3)
示例:利用交互递归来判断一个数的奇偶性
package NO4;
//利用交互递归来实现判断一个数是否是偶数
public class Test28 {
static boolean isEven(int n){ //判断是否是偶数
if(n == 0) //此为递归的出口
return true;
else
return isOdd(n-1); //输入一个数n,不确定它是否为偶数,则交由isOdd(n-1)判断
}
static boolean isOdd(int n){ //判断是否是奇数,如果他不是偶数,则返回true,若他是偶数,则返回false
return !isEven(n); //调用isEven(n)来判断,返回!isEven(n)
}
public static void main(String[] args) {
// TODO Auto-generated method stub
//System.out.println(isEven(11));
System.out.println(isOdd(11));
}
}
此处空出解释的位置:
交通问题
如图的城市交通网,每个路口都有红绿灯。
某车辆,从A点开始,打算去往B点。
如果只允许车辆向上和向右行驶,那么从A到B有多少种可能的路径?
代码:设A点坐标为(0,0) B点坐标为(m,n)
则到达B点分两种情况,则需要首先到达点(m-1,n) 或点(m,n-1),后面一直可以继续递归
边界条件为当m == 0 或者 n == 0时候,返回1
package NO4;
public class Test30 {
static int f(int m, int n){
if(m == 0) return 1;
if(n == 0) return 1;
return f(m-1, n) + f(m, n-1);
}
public static void main(String[] args) {
// TODO Auto-generated method stub
//System.out.println(f(1, 2));
System.out.println(f(4, 4));
//f(m, n);
}
}
f(4,4)的结果为70
f(2,2)的结果为6
f(8,8)的结果为12870 好大呀 = =