轉載:動態規劃之公共串
概念:
動態規劃(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]);