转载:动态规划之公共串
概念:
动态规划(Dynamic programming,简称DP),是大家都觉得比较难以掌握的算法。为了应付面试,我们经常会背诵一下斐波那楔数列或者揹包问题的源码,其实,只要理解了思想,掌握基本的模型,然后再来点写代码的套路,动态规划并没有那么难。
首先,动态规划最重要的是掌握他的思想,动态规划的核心思想是把原问题分解成子问题进行求解,也就是分治的思想。
经典模型
1.线性模型
最经典的问题就是斐波那楔数列的问题,每个数的值都是一个状态,可以用F[i]表示表示第i个数的值是多少。每个数都是由F[i-1]+F[i-2]转移而来。
另外一个经典的问题就是最长上升自序列(LIS),有一串序列,要求找出它的一串子序列,这串子序列可以不连续,但必须满足它是严格的单调递増的且为最长的。把这个长度输出。示例:1 7 3 5 9 4 8 结果为4。
我们非常容易表示他的状态,我们用f[i]表示以第i个数结尾的,最大的上升自序列是多少?那么它是怎么转移的呢?非常容易想到肯定是从左边的的数转移而来,能转移的数满足什么条件呢?肯定是比a[i]更小的。
线性模式还可以拓展成二维问题,例如揹包问题,用f[i][j]表示前i个物品,凑成大小为j的揹包,最大的价值是多少。
这类问题非常的多,但是思路都是这样,无非就是从左往右,从上到下,从低维到高维进行转移。
2.区间模型
3.树状模型
常见案例:
1.爬楼梯
假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
注意:给定 n 是一个正整数。
class Solution {
public int climbStairs(int n) {
//1.特判
if(n < 3) return n;
//2.边界
int[] dp = new int[n+1]; //楼梯:1-n
dp[1] = 1;
dp[2] = 2;
//3.状态转移方程
for(int i = 3;i <= n;i++){
dp[i] = dp[i-1] + dp[i-2];
}
return dp[n];
}
}
最长公共子串递推公式:(连续)
递推公式:
1 if(s1.charAt(i) == s2.charAr(j))
2 dp[i][j] = dp[i-1][j-1] + 1;
3 else
4 dp[i][j] = 0;
1public static int maxLong(String str1, String str2) {
2 if (str1 == null || str2 == null || str1.length() == 0 || str2.length() == 0)
3 return 0;
4 int max = 0;
5 int[] dp = new int[str2.length() + 1];
6 for (int i = 1; i <= str1.length(); i++) {
7 for (int j = str2.length(); j >= 1; j--) {
8 if (str1.charAt(i - 1) == str2.charAt(j - 1))
9 dp[j] = dp[j - 1] + 1;
10 else
11 dp[j] = 0;
12 max = Math.max(max, dp[j]);
13 }
14 Util.printIntArrays(dp);//这一行和下面一行是打印测试数据的,也可以去掉
15 System.out.println();
16 }
17 return max;
18}
子序列:(不连续)
1 if(s1.charAt(i) == s2.charAr(j))
2 dp[i][j] = dp[i-1][j-1] + 1;
3 else
4 dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);