算法(动态规划)
动态规划
基本思想
将问题分解为相互重叠的子问题
- 定义子问题:将原问题分解为若干个子问题。
- 确定状态转移方程:找到子问题之间的递推关系。
- 边界条件:确定初始状态的值。
- 递推计算:根据状态转移方程和边界条件逐步计算子问题的解。
应用场景
- 最短路径问题
- 最长公共子序列:求解两个序列的最长公共子序列。
- 字符串编辑距离:求解两个字符串之间的编辑距离。
五部曲
- 确定dp数组以及下标的含义
- 确定递推公式
- dp数组如何初始化
- 确定遍历顺序
- 举例推导dp数组
常见算法
爬楼梯
class Solution {
public int climbStairs(int n) {
int[] dp = new int[n + 1];
dp[0] = 1;
dp[1] = 1;
for(int i = 2; i <= n; i++) {
dp[i] = dp[i - 1] + dp[i - 2];
}
return dp[n];
}
}
斐波那契数列
public class Fibonacci {
public static int fib(int n) {
if (n <= 1) {
return n;
}
int[] dp = new int[n + 1];
dp[0] = 0;
dp[1] = 1;
for (int i = 2; i <= n; i++) {
dp[i] = dp[i - 1] + dp[i - 2];
}
return dp[n];
}
public static void main(String[] args) {
int n = 10;
System.out.println("Fibonacci(" + n + ") = " + fib(n));
}
}
最长公共子序列
public class LongestCommonSubsequence {
public static int lcs(String s1, String s2) {
int m = s1.length();
int k = s2.length();
int[][] dp = new int[m + 1][k + 1];
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= k; j++) {
if (s1.charAt(i - 1) == s2.charAt(j - 1)) {
dp[i][j] = dp[i - 1][j - 1] + 1;
} else {
dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
}
}
}
return dp[m][k];
}
public static void main(String[] args) {
String s1 = "ABCBDAB";
String s2 = "BDCABA";
System.out.println("最长公共子序列长度:" + lcs(s1, s2));
}
}