动态规划:通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。
动态规划常常适用于有重叠子问题和最优子结构性质的问题。
基本思想
若要解一个给定问题,我们需要解其不同部分(即子问题),再合并子问题的解以得出原问题的解。 通常许多子问题非常相似,为此动态规划法试图仅仅解决每个子问题一次,从而减少计算量: 一旦某个给定子问题的解已经算出,则将其记忆化存储,以便下次需要同一个子问题解之时直接查表。 这种做法在重复子问题的数目关于输入的规模呈指数增长时特别有用。
分治与动态规划
共同点:二者都要求原问题具有最优子结构性质,都是将原问题分而治之,分解成若干个规模较小(小到很容易解决的程序)的子问题.然后将子问题的解合并,形成原问题的解.
不同点:分治法将分解后的子问题看成相互独立的,通过用递归来做。
动态规划将分解后的子问题理解为相互间有联系,有重叠部分,需要记忆,通常用迭代来做。
问题特征
最优子结构:当问题的最优解包含了其子问题的最优解时,称该问题具有最优子结构性质。
重叠子问题:在用递归算法自顶向下解问题时,每次产生的子问题并不总是新问题,有些子问题被反复计算多次。动态规划算法正是利用了这种子问题的重叠性质,对每一个子问题只解一次,而后将其解保存在一个表格中,在以后尽可能多地利用这些子问题的解。
步骤
描述最优解的结构,确定是否可以使用动态规划
递归定义最优解的值
按自底向上的方式计算最优解的值,初始化起始值
由计算出的结果构造一个最优解
注意的两点:边界的处理和递归的使用
来个例子体验一把:
题目描述
Given s1, s2, s3, find whether s3 is formed by the interleaving of s1 and s2.
For example,
Given:
s1 ="aabcc",
s2 ="dbbca",
When s3 ="aadbbcbcac", return true.
When s3 ="aadbbbaccc", return false.
思路:s3是由s1和s2交织生成的,意味着s3由s1和s2组成,在s3中s1和s2字符的顺序是不能变化的,和子序列题型类似,这种题我们一般是用动态规划来解。
- 设dp[i][j]表示s3的前i+j个字符可以由s1的前i个字符和s2的前j个字符交织而成。
- 状态转移方程:有两种情况
- 第一个状态转移方程:
dp[i][j]= dp[i-1][j] && (chs3[i+j-1] == chs1[i-1])
dp[i-1][j]表示若s3的前i+j-1个字符能够由s1前i-1个字符和s2的前j个字符交织而成,那么只需要s1的第i个字符与s3的第i+j个字符相等,那么dp[i][j]=true; - 第二个状态转移方程:
dp[i][j]=dp[i][j-1] && (chs3[i+j-1] == chs2[j-1]
dp[i-1][j]表示若s3的前i+j-1个字符能够由s1前i个字符和s2的前j-1个字符交织而成,那么只需要s2的第j个字符与s3的第i+j个字符相等,那么dp[i][j]=true
- 第一个状态转移方程:
import java.util.*; public class Solution { public boolean isInterleave(String s1, String s2, String s3) { int len1=s1.length(); int len2=s2.length(); int len3=s3.length(); if(len1+len2!=len3){ return false; } char[] chs1 = s1.toCharArray(); char[] chs2 = s2.toCharArray(); char[] chs3 = s3.toCharArray(); boolean dp[][]=new boolean[len1+1][len2+1]; //初始化 s1中取0个字符 s2中取0个字符 匹配s3从0开始的0个字符 肯定匹配true dp[0][0] = true; for(int i=1;i<len2+1;i++){ dp[0][i]=dp[0][i-1]&&(chs2[i-1]==chs3[i-1]); } for(int i=1;i<len1+1;i++){ dp[i][0]=dp[i-1][0]&&(chs1[i-1]==chs3[i-1]); } for(int i = 1 ; i < len1+1 ; i ++ ){ for(int j = 1 ; j < len2+1 ; j ++ ){ dp[i][j] = dp[i-1][j] && (chs3[i+j-1] == chs1[i-1]) || dp[i][j-1] && (chs3[i+j-1] == chs2[j-1]); } } return dp[len1][len2]; } }