1,1,2,3,5,8,13,..... f(n) = f(n-1) + f(n-2)
代码实现
public static int count_2 = 0;
public int fibonacci(int n){
if (n <= 2){
count_2++;
return n;
}
int f1 = 1;
int f2 = 2;
int sum = 0;
for (int i = 3; i < n; i++) {
count_2++;
sum = f1 + f2;
f1 = f2;
f2 = sum;
}
return sum;
}
当n=20时,count是21891次,当n=30的时候结果是2692537,接近270万,为什么这么高,因为里面存在大量的循环,下面图中,n=8时,f(6)就重复计算两次,很多结点会被重复计算。
如何将其优化减少重复计算,这也是下面推导动态规划需要考虑的,可以将计算结果保存到数组中,f(n)的值保存在数组中,f(n)=arr[n],某个位置已经被计算出来,下次需要的时候直接取出来,不需要再递归。
public static int[] arr = new int[50];
public static int count_3 = 0;
public static void main(String[] args) {
Arrays.fill(arr,-1);
arr[0] = 1;
System.out.println(fibonacci(31));
}
static int fibonacci(int n){
if (n == 2 || n == 1){
count_3++;
arr[n] = n;
return n;
}
if (arr[n] != -1){
count_3++;
return arr[n];
}else {
count_3++;
arr[n] = fibonacci(n - 1) + fibonacci(n - 2);
return arr[n];
}
}
文中的动态规划我们简称DP,路径相关的问题来分析动态规划,路径问题易于画图,方便理解,循序渐进的理解DP
LeetCode62 一个机器人位于一个 m x n
网格的左上角 (起始点在下图中标记为 “Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。
问总共有多少条不同的路径?
第一炮,我们研究如何通过递归来解决此问题,如下图所示,从起点开始要么向右,要么向下,每一种否会导致剩下的区间减少了一列或一行,形成两个不同区间的过程,每个区间继续以红点为起点继续上述操作,所以这就是一个递归的过程,
从图中寻找规律,目标从起点到终点,只能向右或向下,
1. 向右走一步,起点下面灰色的不会再被访问,后面剩一个3X1的矩阵,只能一直往下走,只有一种路径,
2. 向下走一步,起点右侧不不能再被访问,剩一个2X2的矩阵,还剩两种路径,
这是3X2的矩阵,一共有3中路径,一个2X2的矩阵和3X1的矩阵路径之和。
同样我们推导一个3X3的矩阵,就是一个3X2的矩阵和2X3的路径之和,
所以,对于一个mxn的矩阵,求路径的方法是serch(m,n)=search(m-1,n)+search(m,n-1);
public int uniquePath(int m,int n){
return search(m,n);
}
private int search(int m, int n) {
if (m == 1 || n == 1){
return 1;
}
return search(m-1,n) + search(m,n-1);
}
对于3X3的矩阵,我们可以用二叉树表示
我们可以发现,和文章开头我们提到的一样,中间有重复计算,1,1计算了两次,那么如何优化
我们知道上面出现了重复计算,{1,1}出现两次,在{1,1}位置处,不管是从{0,1}还是{1,0}到来,都会产生两种走法,我们可以用二维数组记忆化搜索就不用两次遍历了,
每个格子都表示从起点开始到当前的位置有几种方式,这样我们通过计算路径的时候可以先查下二维数组有没有记录,有就直接读,没有再计算,这样就可以避免大量的重复计算,这就是记忆化搜索。
从上面的分析我们得到两个规律:
1.第一行和第一列都是1.
2.其他格子的值都是其左侧和上方格子之和,对于mXn的格子都适应。
public int uniquePath(int m, int n){
int[][] f = new int[m][n];
f[0][0] = 1;
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (i > 0 && j > 0){
f[i][j] = f[i -1][j] + f[i][j -1];
}else if (i > 0){
f[i][j] = f[i -1][j];
} else if (j > 0) {
f[i][j] = f[i][j -1];
}
}
}
return f[m -1][n -1];
}
持续更新。。。。