动态规划算法入门(一)(java语言)

                           动态规划入门(一)

动态规划算法是试图求解无法用贪心法和分治法获得最有解的问题。

动态规划(Dynamic Programming,DP)是一项虽简单但较难掌握的技术。

动态规划的定义:

     动态规划和备忘录共同作用。动态规划和分治法的主要区别是:对于后者,子问题是相互独立的,而在动态规划中子问题可能是重叠的,通过使用备忘录(用一个表来保存已解决子问题的答案),对于大部分问题,动态规划能够将带求解问题的复杂度由指数级降为多项式级。动态规划主要包含两部分:

               递归:递归求解子问题。

               备忘录:将已计算的值存储在表中。

                                             动态规划=  递归 + 备忘录

动态规划的性质:

      以下两条性质可用于判断动态规划方法是否可用于给定的问题:

               最优子结构:问题的最优解包含其子问题的最优解。

              子问题重叠:递归求解过程中包含少量不同子问题的多次重复计算。

动态规划的实现方法:

        有两种基本的实现方法:

            1.自底向上动态规划法

            2.自顶向下动态规划法

动态规划算法的例子:

         -------->许多字符串算法,如最长公共子序列、最长递增子序列,最长公共字串、编辑距离等

         -------->关于图的有效求解算法:寻找图中最短距离的Bellman-Ford算法、Floyd的所有顶点间最短路径算法等。

         -------->链矩阵乘法。

        -------->子集和

        -------->0/1背包问题

        -------->旅行商问题

具体示例(java语言):

    求解斐波那契数列。代码中使用了四种不同方法。

源代码:

import java.util.Scanner;

/**
 * 动态规划算法
 */
public class Fibonacci {

	public static void main(String[] args) {
		Fibonacci fibonacci = new Fibonacci();
		Scanner scanner = new Scanner(System.in);
		int n = scanner.nextInt();

		int sum = fibonacci.recursiveFibonacci(n); // 递归实现
		System.out.println("递归实现:" + sum);

		int fib[] = new int[n + 1];
		int sumOfFibo = fibonacci.fibo(n, fib);
		System.out.println("自顶向下实现:" + sumOfFibo);

		int sumOfFib = fibonacci.fib(n);
		System.out.println("自底向上实现:" + sumOfFib);

		int sumOfFibon = fibonacci.fibon(n);
		System.out.println("改进算法:" + sumOfFibon);
	}

	// 递归实现(时间复杂度为:2的n次方)
	public int recursiveFibonacci(int n) {
		if (n == 0)
			return 0;
		if (n == 1)
			return 1;
		return recursiveFibonacci(n - 1) + recursiveFibonacci(n - 2);
	}

	/*
	 *  动态规划算法实现之自底向上(时间复杂度为:O(n);空间复杂度为:O(n)):
	 *  从输入的最小参数值开始,逐步构建更大参数值的解
	 */
	public static int fib(int n) {
		int[] fib = new int[n];
		if (n == 0)
			return 0;
		if (n == 1)
			return 1;
		if (n > 1) {
			fib[0] = 1;
			fib[1] = 1;
		}
		for (int i = 2; i < n; i++) {
			fib[i] = fib[i - 1] + fib[i - 2]; // 动态规划,把值记录在备忘录中
		}
		return fib[n - 1];
	}

	/*
	 * 动态规划算法实现之自顶向下(时间复杂度为:O(n);空间复杂度为:O(n)):
	 * 在该方法中保留递归调用,如果某个子问题的解已计算则使用该值
	 */
	public int fibo(int n, int[] fib) {
		if (n == 0)
			return 0;
		if (n == 1)
			return 1;
		if (n == 2)
			return 1;
		if (fib[n] != 0) {
			return fib[n];
		}
		return fib[n] = fibo(n - 1, fib) + fibo(n - 2, fib);
	}

	/*
	 * 进一步改进:进一步观察斐波那契数列可以发现:当前值仅仅是前两次计算结果之和。
	 * 这意味着不需要存储多有先前的返回值,而只需要存储最后两次计算的值就能计算出当前值。
	 *  该算法的时间复杂度为O(n),空间复杂度为:O(10)。
	 */
	public int fibon(int n) {
		if (n == 0)
			return 0;
		if (n == 1)
			return 1;
		int a = 0, b = 1, sum = -1, i;
		for (i = 1; i < n; i++) {
			sum = a + b;
			a = b;
			b = sum;
		}
		return sum;
	}
}


运行结果截图:


PS:欢迎大家提出不同的看法或思路。欢迎大家来评论,一起学习交流进步。



猜你喜欢

转载自blog.csdn.net/alan_gaohaodong/article/details/78902900