将分门别类的对常见DP问题进行总结,文末附有GitHub链接
字符串问题
回文子串是连续的,而子序列则不一定连续。
5.最长回文子串
647.回文子串
516.最长回文子序列
1143.最长公共子序列
最长公共子串
public int getLCS(String s, String t) {
if (s == null || t == null) {
return 0;
}
int result = 0;
int sLength = s.length();
int tLength = t.length();
int[][] dp = new int[sLength + 1][tLength + 1];
for (int i = 1; i <= sLength; i++) {
for (int k = 1; k <= tLength; k++) {
if (s.charAt(i - 1) == t.charAt(k - 1)) {
dp[i][k] = dp[i - 1][k - 1] + 1;
result = Math.max(dp[i][k], result);
}
}
}
return result;
}
股票问题
121.买卖股票的最佳时机
122.买卖股票的最佳时机II
123.买卖股票的最佳时机III
188.买卖股票的最佳时机IV
309.最佳买卖股票时机含冷冻期
714.买卖股票股票最佳时机含手续费
最长子序列问题
300和646的不同之处在于646会先排序,因此可以返回dp[len-1],而300是无序的,因此需要返回以全局的Max。
300.最长上升子序列
646.最长数对链
673.最长递增子序列的个数
712.两个字符串的最小ASCII删除和
413.等差数列划分
0-1背包问题
416.分割等和子集
1049.最后一块石头的重量II
474.一和零
有 N 件物品和一个容量为 V 的背包。第 i 件物品的体积是 C[i],价值是 W[i]。求解将哪些物品装入背包可使价值总和最大,求出最大总价值。
public static int zeroOnePack(int V, int[] C, int[] W){
if(V <= 0 || C.length != W.length)
return 0;
int n = C.length;
int[][] dp = new int[n + 1][V + 1];
for(int i = 0; i <= n; i++){
for(int j = 0; j <= V; j++){
if(j < C[i - 1])// 背包放不下第 i 个物品
dp[i][j] = dp[i - 1][j];
else// 背包能放下第 i 个物品,选择价值最大的方案
dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - C[i - 1]] + W[i - 1]);
}
}
return dp[n][V];
}
空间优化:
public static int zeroOnePackOpt(int V, int[] C, int[] W){
if(V <= 0 || C.length != W.length)
return 0;
int n = C.length;
int[] dp = new int[V + 1];
dp[0] = 0;// 背包为空时,价值为 0
for(int i = 0; i < n; i++){
for(int j = V; j >= C[i]; j--){
dp[j] = Math.max(dp[j], dp[j - C[i]] + W[i]);
}
}
return dp[V];
}
两个人抓数问题
视频拼接问题
零钱兑换问题
马跳棋盘问题
688.“马”在棋盘上的概率
576.出界的路径数
935.骑士拨号器
连续子序列/打家劫舍问题
152.乘积最大子序列
53.最大子序和
713.成绩小于K的子数组
198.打家劫舍
213.打家劫舍II
337.打家劫舍III
二叉搜索树与Dp
路径问题
其他
467.环绕字符串中唯一的子字符串
91.解码方法
873.最长的斐波那锲子序列的长度
898.子数组按位或操作
221.最大正方形
801.使序列递增的最小交换
1027.最长等差数列
139.单词拆分
837.新21点
877.石子游戏
368.最大整除子集
813.最大平均值和的分组
120.三角形最小路径和
有 N 堆金币排成一排,第 i 堆中有 C[i] 块金币。每次合并都会将相邻的两堆金币合并为一堆,成本为这两堆金币块数之和。经过N-1次合并,最终将所有金币合并为一堆。请找出将金币合并为一堆的最低成本。其中,1 <= N <= 30,1 <= C[i] <= 100
//dp[i][j]:i-j的最小和
import java.util.*;
class Test{
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int[] coin = new int[n+1];
int[] preSum = new int[n+1];
for(int i=1;i<=n;i++) {
coin[i] = in.nextInt();
if(i==1) preSum[i]=coin[i];
else preSum[i]=preSum[i-1]+coin[i];
}
in.close();
int[][] dp=new int[n+1][n+1];//i-j的最低成本
for(int len=2;len<=n;len++){
for(int i=1;i<=n-len+1;i++){
int j=i+len-1;
dp[i][j]=Integer.MAX_VALUE;
int sum=preSum[j]-preSum[i-1];
for(int k=i;k<j;k++){
dp[i][j]=Math.min(dp[i][j],dp[i][k]+dp[k+1][j]+sum);
}
}
}
System.out.println(dp[1][n]);
}
}