1.整数拆分
递归公式
dp(n,k) = 1 n =1,k =1
dp[n,k] = dp[n,n] n < k
dp[n,k] = dp[n,n-1]+1 n =k
dp[n,k] = dp[n,k-1] + dp[n-k,k] n > k
代码
// 题目描述:将正整数n无序拆分成最大数为k的拆分情况。拆分方案不重复
public static int split(int n,int k){
int [][] dp = new int[n+1][k+1];
dp[0][0] = 0;
int i, j;
for (i = 1; i <= n; i++){
for (j = 1; j <= k; j++){
// n = 1 ,k = 1时候 dp[i][j] = 1
if (i == 1 || j == 1){
dp[i][j] = 1;
}else if(i < j){
dp[i][j] = dp[i][i];
}else if (i == j){
dp[i][j] = dp[i][j-1] + 1;
}else if(i > j){
dp[i][j] = dp[i-j][j] + dp[i][j-1];
}
}
}
return dp[n][k];
}
2.最长公共子序列
递归公式
c[i][j] = c[i-1][j-1] +1 -------------------- 当 a[i-1] = b[j-1]
c[i][j] = max(c[i][j-1],c[i-1][j]) ---------- 当a[i-1] 不等于 b[j-1]
代码
// 求最长公共子序列的长度
public static int commonLen(String s1,String s2){
int len1 = s1.length();
int len2 = s2.length();
// 进行空与字符串比较 【特殊情况】
for (int i = 0; i <= len1; i++){
dp[i][0] = 0;
}
for (int i = 0; i <= len2;i++){
dp[0][i] = 0;
}
for (int i = 1; i <= len1; i++){
for (int j = 1; j <= len2;j++){
// 如果两者相等,则选择左上角+1
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[len1][len2];
}
3.0/1背包
递推公式
f(i,r) = f(i-1,r) ---------- 当 r < wi
f(i,r) = max(f(i-1,r), f(i-1,r-wi)+vi) ---------- 当r >= wi
代码
public static int knep(int f[][],int w[],int val[],int W,int n){
// 边界初始化操作:当W=0时候
for (int i = 0; i <= n;i++)
f[i][0] = 0;
// 边界初始化操作:当w[i] = 0的时候。
for (int r = 0; r <= W;r++)
f[0][r] = 0;
// 遍历操作
for (int i = 1; i <= n;i++){
for (int r=1; r <= W;r++){
// 装不下时候,不装。
if (r < w[i]){
f[i][r] = f[i-1][r];
}else{
// 装得下,比较是否要装入。
f[i][r] = Math.max(f[i-1][r],f[i-1][r-w[i]]+val[i]);
}
}
}
return f[n][W];
}
4.完全背包
递归公式:
f(i,j) = max( f(i, j-k*w[i])+v[i] , f[i-1][j])
代码
public static int solve(int w[],int f[][],int val[],int W,int n){
for (int i = 1; i <= n;i++){
for (int j = 1; j <= W;j++){
// 放不下
if (j - w[i-1] < 0){
f[i][j] = f[i-1][j];
}else{ // 放的下
// 放:几次
if (f[i-1][j] < f[i][j -w[i-1]] +val[i-1]){
// 注意这里是f[i][j-w[i]] 表示当前的物品能够放几次。
f[i][j] = f[i][j-w[i-1]] +val[i-1];
}else{
// 不放
f[i][j] = f[i-1][j];
}
}
}
}
return f[n][W];
}
5.最大连续子序列和
递推公式
bi = max(bi-1+ai,ai)
代码
public static int[] lcs(int[]a){
int n = a.length;
int b[] = new int[n+1];
b[0] = a[0];
int j =1;
for (int i=1; i < n;i++){
b[j] = Math.max(b[j-1]+a[i],a[i]);
j++;
}
return b;
}
6.单调递增子序列
递推公式
b[i] = max(b[k]) +1
代码
public static int lis(int [] a){
int len = a.length;
int b[] = new int[len];
b[0] = 1;
for (int i =1; i < len;i++){
int k = 0;
for (int j = 0; j < i; j++){
// 递增且获取之前存储过最大的连续递增长度
if (a[j] <= a[i] && k < b[j]){
k = b[j];
}
}
b[i] = k+1;
}
return b[len-1];
}