Java动态规划概述
动态规划(Dynamic Programming, DP)是一种解决复杂问题的算法思想,它将问题分解为子问题,通过存储子问题的解来避免重复计算,从而提高效率。在Java中实现动态规划通常涉及以下几种方式:
动态规划的基本实现方式
1. 自顶向下(记忆化递归)
java
import java.util.Arrays;
public class MemoizationExample {
private int[] memo;
public int fibonacci(int n) {
memo = new int[n + 1];
Arrays.fill(memo, -1);
return fibHelper(n);
}
private int fibHelper(int n) {
if (n <= 1) return n;
if (memo[n] != -1) return memo[n];
memo[n] = fibHelper(n - 1) + fibHelper(n - 2);
return memo[n];
}
}
2. 自底向上(迭代法)
java
public class BottomUpExample {
public int fibonacci(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];
}
}
经典动态规划问题示例
1. 0-1背包问题
java
public class Knapsack {
public int knapsack(int W, int[] wt, int[] val, int n) {
int[][] dp = new int[n + 1][W + 1];
for (int i = 0; i <= n; i++) {
for (int w = 0; w <= W; w++) {
if (i == 0 || w == 0) {
dp[i][w] = 0;
} else if (wt[i - 1] <= w) {
dp[i][w] = Math.max(val[i - 1] + dp[i - 1][w - wt[i - 1]], dp[i - 1][w]);
} else {
dp[i][w] = dp[i - 1][w];
}
}
}
return dp[n][W];
}
}
2. 最长公共子序列
java
public class LCS {
public int longestCommonSubsequence(String text1, String text2) {
int m = text1.length(), n = text2.length();
int[][] dp = new int[m + 1][n + 1];
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
if (text1.charAt(i - 1) == text2.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][n];
}
}
3. 硬币找零问题
java
import java.util.Arrays;
public class CoinChange {
public int coinChange(int[] coins, int amount) {
int[] dp = new int[amount + 1];
Arrays.fill(dp, amount + 1);
dp[0] = 0;
for (int i = 1; i <= amount; i++) {
for (int coin : coins) {
if (coin <= i) {
dp[i] = Math.min(dp[i], dp[i - coin] + 1);
}
}
}
return dp[amount] > amount ? -1 : dp[amount];
}
}
动态规划四要素
- 状态定义:明确DP数组或变量表示什么
- 状态转移方程:找出如何从子问题推导出当前问题的解
- 初始条件:确定基础情况的解
- 计算顺序:确定是自顶向下还是自底向上
优化技巧
- 空间优化:对于某些问题,可以使用滚动数组减少空间复杂度
- 状态压缩:当状态转移只依赖前几个状态时,可以只保存这些状态
- 提前终止:在某些情况下可以提前终止计算
动态规划是解决许多经典问题(如最短路径、资源分配、序列比对等)的强大工具,掌握它需要大量的练习和模式识别。