【动态规划】 习题总结

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];
    }
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值