动态规划的基本思想与例子解析

    经分解得到的子问题有时候往往不是互相独立的。不同子问题的数目常常只有多项式量级。在用分治法求解时,有些子问题被重复计算了许多次。

   Those who cannot remember the pastare doomed to repeat it.        ——George Santayana

   (不取前车之鉴,必将重蹈覆辙。)


1.基本思想

   如果分解得到的子问题不是互相独立的,此时若能够保存已解决的子问题的答案,而在需要时再找出已求得的答案,就可以避免大量重复计算,从而提高计算效率。
动态规划的基本思想与例子解析_第1张图片

2.解题步骤

I.找出最优解的性质,并刻划其结构特征。(最优子结构)
II.递归地定义最优值。
III.自底向上的方式计算出最优值。
IV.根据计算最优值时得到的信息,构造最优解

3.动态规划的应用例子

(a) 最大连续乘积子数组

I.问题描述:任意取出数组中的若干个连续的数相乘,找出其中乘积最大的子数组
II.解题思路:考虑到负数的存在,即负负得正的情况可能成为乘积最大的子数组,故需要同时并记录找出最大乘积和最小乘积
III.递归结构:maxEnd = max(max(maxEnd * a[i], minEnd * a[i]), a[i]);
                      minEnd = min(min(maxEnd * a[i], minEnd * a[i]), a[i]);
IV.一层for循环,时间复杂度为O(n)
	public double maxProductSubstring(double[] a){
		double maxEnd = a[0];
		double minEnd = a[0];
		double maxResult = a[0];
		
		for (int i = 1; i < a.length; i++) {
			double end1 = maxEnd * a[i], end2 = minEnd * a[i];
			maxEnd = Math.max(Math.max(end1, end2), a[i]);
			minEnd = Math.min(Math.min(end1, end2), a[i]);
			maxResult = Math.max(maxEnd, maxResult);
		}
		return maxResult;
	}

(b) 0-1背包问题

I.问题描述:一共有n件物品,对每一件物品i都有两种选择,即装入背包或不装入。一件物品只能装一次且不能装入部分物品
II.递归结构:
动态规划的基本思想与例子解析_第2张图片
	public static int package0_1(int[] v, int[] w,int Max){
		int len = v.length;
		int[] dp = new int[len];
		
		for (int i = 0; i < len; i++) {
			for (int j = Max; j >= w[i]; j--) {
				dp[j] = Math.max(dp[j], dp[j - w[i]] + v[i]);
			}
		}
		
		return dp[len];
	}

(c) 最长公共子序列(LCS)

I.问题描述:给定2个序列X和Y,当另一序列Z既是X的子序列又是Y的子序列时,称Z是序列X和Y的公共子序列,求X、Y的最长公共子序列
II.最优子结构:
动态规划的基本思想与例子解析_第3张图片
III.递归结构:
动态规划的基本思想与例子解析_第4张图片
IV.对于m*n个子问题均需要计算一次,故时间复杂度为O(m*n)
V.递归结构中空间复杂度为O(m*n),可优化为O(min(m,n))
	public static int lcsLength(char[] x, char[] y){
		int m = x.length;
		int n = y.length;
		int k = m > n ? n : m;
		int[] c = new int[k+1];
		int leftabove, above;
		
		for (int i = 1; i <= m; i++) {
			leftabove = c[0];  
			above = c[1];  
			
			for (int j = 1; j <= n; j++) {
				if(x[i-1] == y[j-1]){
					c[j] = leftabove + 1;
				}
				else{
					c[j] = Math.max(c[j], c[j-1]);
				}
				
				//更新变量
				leftabove = above;  
	            above = c[(j+1) % n];    
			}
		}
		
		return c[k];
	}


你可能感兴趣的:(算法)