递归能够很方便的解决不少问题,让程序变得很简洁。java
可是,在递归解决问题的过程成,有时候会有不少重复计算,使得计算量很大,耗时很长。数组
好比,使用递归求斐波那契数列。ide
若是用普通的递归来解,当n值很大时,时间会很长而超时。学习
如图,当n等于45时,须要运行5秒才能求出结果。优化
分析一下,会是什么缘由致使须要计算这么长时间呢?code
根据斐波那契数列的递推公式:blog
fn=f(n-1)+f(n-2)递归
f(n-1)=f(n-2)+f(n-3)
f(n-2)=f(n-3)+f(n-4);
以上3行合并一下:
fn=( f(n-2)+f(n-3) ) + ( f(n-3)+f(n-4) )源码
能够看到, f(n-3)被重复计算了。it
再看一下斐波那契数列的运行时图:
能够看到,有大量的重复计算。
有没有什么办法能够优化呢?
若是咱们能记录一些状态的中间结果,在须要的时候直接读取结果,就能够减小重复计算。
这个思想叫着记忆化。
对于斐波那契数列,咱们能够把计算完 n=2,n=3时...的值保存在数组中,下次须要使用他们来计算其余n值时,从数组中取出来,而不去再计算。
按照这个思想,代码修改成:
能够看到,通过记忆化优化后的程序,运行速度快了不少。
下面咱们再看个例子。
5
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
如上图所示,第一行有一个数字5,表示数字三角形共有5层。
后面5行为各层的数字,组成一个数字三角形。
给出一个三角形,从三角形的顶点,只能走左下方或者右下方,而后把所遍历的数字加起来,求出最大的值。
好比对于上图来讲,答案就是30(7+3+8+7+5)。
现给定一个任意的数字三角形,输出最大的值。
咱们从顶点(也就是第一行第一列)开始走,其最大值为顶点的值加上从他下面两个数开始,走到底边的最大值中,更大的那个,由此,咱们把问题分解成求第一行的数字到底边的最大值,到求第二行的数字到底边的最大值,这就造成了递归。
而递归的终止条件是到了最后一行,其值就是它自己。
递归的代码以下:
package test; import java.util.Scanner; public class Hello { static int d[][] = new int[100][100]; // 最多100层 static int n; public static void main(String[] args) { Scanner sc = new Scanner(System.in); n = sc.nextInt(); // 总共有几层 for (int i = 1; i <= n; i++) for (int j = 1; j <= i; j++) d[i][j] = sc.nextInt(); int m = MaxSum(1, 1); System.out.println("最大值:"+m); } static int MaxSum(int l, int r) { if (l == n) return d[l][r]; else return Math.max(MaxSum(l + 1, r), MaxSum(l + 1, r + 1)) + d[l][r]; } }
样例输入输出:
输入:
6
2
96 30
83 52 60
21 65 44 61
8 79 50 41 21
61 41 50 38 79 10
输出
375
若是经过记忆化进行优化呢?
思考一下........
....................................................................................................................
public class Hello { static int d[][] = new int[100][100]; // 最多100层 static int max[][]= new int[100][100]; //保存记忆 static int n; public static void main(String[] args) { Scanner sc = new Scanner(System.in); n = sc.nextInt(); // 总共有几层 for (int i = 1; i <= n; i++) for (int j = 1; j <= i; j++) d[i][j] = sc.nextInt(); int m = MaxSum(1, 1); System.out.println("最大值:"+m); } static int MaxSum(int l, int r) { if (l == n) return d[l][r]; else { if(max[l][r]!=0) { return max[l][r]; }else { int x=Math.max(MaxSum(l + 1, r), MaxSum(l + 1, r + 1)) + d[l][r]; max[l][r]=x; return x; } } } }
源码、更多资深讲师相关课程资料、学习笔记请入群后向管理员免费获取,更有专业知识答疑解惑。入群即送价值499元在线课程一份。
QQ群号:560819979敲门砖(验证信息):高山流水