一、动态规划、分治、递归的概念
动态规划:如果大问题分解为很多小问题后,小问题有互相重叠部分,则用递归的思路来分析问题,再使用存储中间结果+循环的思路来写代码!动态规划的三个特征:适用于最优解问题、有大量的重复子问题、子问题之间有依赖(不独立)
与递归的关系:这些重复的子问题,DP算法将其结果用一维或二维数组(邻接矩阵)保存下来,等下一次又要计算该子问题时,直接用已计算好的;而递归却不是这样,它会一遍又一遍地计算这些重复的子问题,从而效率狂降。子问题重复率较高的递归算法可改写成动态规划,但不是所有递归算法都适合改成动态规划。
与分治的关系:在分治法中,有大量的重复子问题,且它们之间无依赖。
二、优化斐波那契数列
package me.ele;
/**
* 动态规划的两种类型
* 1.自顶向下的动态规划实现:用的递归。
* 2.自底向上的动态规划实现:用的迭代。
*
* @author LZJ
* @create 2018-09-29 17:29
**/
public class Fibonacci {
/**
* 普通的递归实现的动态规划:效率特别低,有大量的重复计算,指数级的时间复杂度。
*
* @param n
* @return
*/
public static int fibonacci01(int n) {
if (n == 0)
return 0;
if (n == 1)
return 1;
return fibonacci01(n - 1) + fibonacci01(n - 2);
}
/**
* 自底向上的动态规划实现:会记录重复子问题结果的改进版迭代。
* 只要有存储已经计算出的值的空间,就能把这项技术应用到任何递归计算中,就能把算法从指数级运行时间向线性时间改进。
*
* @param n
* @return
*/
public static long fibonacci02(int n) {
long temp[] = new long[n];
temp[0] = 0;
temp[1] = 1;
for (int i = 2; i < n; ++i) {
temp[i] = temp[i - 1] + temp[i - 2];
}
return temp[n - 1];
}
public static long[] mArray;
/**
* 自顶向下的动态规划实现:会记录重复子问题结果的改进版递归。存储它所计算的每一个值(正如下方代码最末的步骤),
* 并通过检查所存储的值,来避免重新计算它们的任何项(正如最初的步骤)。
*
* @param n
* @return
*/
public static long fibonacci03(int n) {
//不等于初始值0,则表示该元素已经求解过了,直接用其值即可。
if (mArray[n] != 0) {
return mArray[n];
}
//完成按着递推式来写逻辑,即可!
if (n == 0) {
return mArray[n] = 0;
}
if (n == 1) {
return mArray[n] = 1;
} else {
return mArray[n] = fibonacci03(n - 1) + fibonacci03(n - 2);
}
}
public static void main(String[] args) {
int n = 1000;
// System.out.prlongln("===========");
// long start = System.currentTimeMillis();
// System.out.prlongln("start time:" + start);
// long fibonacci01 = fibonacci01(n);
// System.out.prlongln(fibonacci01);
// long end = System.currentTimeMillis();
// System.out.prlongln("end time:" + end + "间隔时间:" + (end - start));
System.out.println("===========");
long start2 = System.currentTimeMillis();
long fibonacci02 = fibonacci02(n + 1);
System.out.println(fibonacci02);
long end2 = System.currentTimeMillis();
System.out.println("end time:" + end2 + "间隔时间:" + (end2 - start2));
System.out.println("===========");
mArray = new long[n + 1];
long start3 = System.currentTimeMillis();
long fibonacci03 = fibonacci03(n);
System.out.println(fibonacci03);
long end3 = System.currentTimeMillis();
System.out.println("end time:" + end3 + "间隔时间:" + (end3 - start3));
}
}