[力扣] 动态规划(DP)问题分类汇总

动态规划是算法面试的一个重点,在力扣上有很多这类题目,题目是刷不完的,将动态规划的全部类型题目刷一遍可以达到事半功倍的效果。

1.线性动态规划

1.1 子序列系列:

题目一:最长上升子序列(300. 最长上升子序列)

题解:注意这里要求的子序列不是连续的,使用动态规划,dp[i]表示的是以下标i的数字作为结尾不连续最长上升子序列的长度,动态转移方程:dp[i] = max{dp[j] + 1, (0 <= j < i,a[j] < a[i]},dp表的初始状态为1,最后统计表中的最大值即为该序列的最长上升子序列。
代码如下:

class Solution {
     
    public int lengthOfLIS(int[] nums) {
     
        // 参数判断
        if (null == nums || 0 == nums.length) {
     
            return 0;
        }
        int[] dp = new int[nums.length];
        int res = 0;
        for (int i = 0; i < nums.length; i ++) {
     
            // 初始值
            dp[i] = 1;
            for (int j = 0; j < i; j ++) {
     
                if (nums[j] < nums[i]) {
     
                    // 在以nums[i]结尾的所有子序列中筛选出最大值
                    dp[i] = Math.max(dp[i], dp[j] + 1);
                }
            }
            // dp表中筛选出最大值即是答案
            res = Math.max(res, dp[i]);
        }
        return res;
    }
}
题目二:最长连续上升子序列(674. 最长连续递增序列)

题解:注意这里求的是连续子序列,使用动态规划,dp[i]表示的是以下标i的数字作为结尾最长连续子序列的长度,动态转移方程:(dp[i] = dp[i - 1] + 1,a[i-1] < a[i];dp[i] = 1,a[i - 1] > a[i]),最后统计表中的最大值即为该序列的最长连续上升子序列。
代码如下:

class Solution {
     
    public int findLengthOfLCIS(int[] nums) {
     
        // 参数判断
        if (null == nums || 0 == nums.length) {
     
            return 0;
        }
        int[] dp = new int[nums.length];
        dp[0] = 1;
        int res = dp[0];
        for (int i = 1; i < nums.length; i ++) {
     
            // nums[i] 大于前面一个nums[i - 1]
            if (nums[i] > nums[i - 1]) {
     
                dp[i] = dp[i - 1] + 1;
            // nums[i] 小于前面一个nums[i - 1],最长连续上升子序列即为他自己    
            } else {
     
                dp[i] = 1;
            }
            // 筛选出最大值即是答案
            res = Math.max(res, dp[i]);
        }
        return res;
    }
}
题目三:最长公共子序列(1143. 最长公共子序列)

题解:状态转移方程:
[力扣] 动态规划(DP)问题分类汇总_第1张图片
代码如下:

class Solution {
     
    public int longestCommonSubsequence(String text1, String text2) {
     
        if (null == text1 || 0 == text1.length() || null == text2 || 0 == text2.length()) {
     
            return 0;
        }    
        int[][] dp = new int[text1.length()][text2.length()];
        char[] t1 = text1.toCharArray();
        char[] t2 = text2.toCharArray();
        dp[0][0] = t1[0] == t2[0] ? 1 : 0;
        for (int i = 1; i < text1.length(); i ++) {
     
            dp[i][0] = Math.max(dp[i - 1][0], t1[i] == t2[0] ? 1 : 0);
        }
        for (int j = 1; j < text2.length(); j ++) {
     
            dp[0][j] = Math.max(dp[0][j - 1], t2[j] == t1[0] ? 1 : 0);
        }
        for (int i = 1; i < text1.length(); i ++) {
     
            for (int j = 1; j < text2.length(); j ++) {
     
                dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
                if (t1[i] == t2[j]) {
     
                    dp[i][j] = Math.max(dp[i][j], dp[i - 1][j - 1] + 1);
                }
            }
        }
        return dp[text1.length() - 1][text2.length() - 1];
    }
}
题目四:最长公共连续子序列

题解:定义状态:dp[i][j]以i为下标a[i],b[j]字符结尾的公共连续子序列。
[力扣] 动态规划(DP)问题分类汇总_第2张图片
代码如下:

public static int lcs(String str1, String str2) {
     
	int len1 = str1.length();
	int len2 = str2.length();
	int result = 0;     //记录最长公共子串长度
	int c[][] = new int[len1+1][len2+1];
	for (int i = 0; i <= len1; i++) {
     
		for( int j = 0; j <= len2; j++) {
     
			if(i == 0 || j == 0) {
     
				c[i][j] = 0;
			} else if (str1.charAt(i-1) == str2.charAt(j-1)) {
     
				c[i][j] = c[i-1][j-1] + 1;
				result = max(c[i][j], result);
			} else {
     
				c[i][j] = 0;
			}
		}
	}
	return result;
}

1.2 股票系列:推荐资料

股票类题解:dp模板,股票类型的题目都是基于这个模板,根据具体的题目来修改调整相应的参数。结果是取没有持有状态下最后一天的dp。因为 [1] 代表手上还持有股票,[0] 表示手上的股票已经卖出去了,很显然后者得到的利润一定大于前者。
[力扣] 动态规划(DP)问题分类汇总_第3张图片

题目一:121. 买卖股票的最佳时机

题解:题目要求最多只进行1次交易,即k = 1,所以

dp[i][k][0] = max(dp[i-1][k][0], dp[i-1][k][1] + prices[i])
dp[i][k][1] = max(dp[i-1][k][1], dp[i-1][k-1][0] - prices[i])
base case
dp[0][k][0] = 0
dp[0][k][1] = -prices[0]

化简为:

dp[i][0] = max(dp[i-1][0], dp[i-1][1] + prices[i])
dp[i][1] = max(dp[i-1][1], - prices[i])
base case
dp[0][0] = 0
dp[0][1] = -prices[0]

代码如下:

class Solution {
     
    public int maxProfit(int[] prices) {
     
        if (null == prices || 0 == prices.length) {
     
            return 0;
        }
        int[][] dp = new int[prices.length][2];
        // base case
        dp[0][1] = -prices[0];
        dp[0][0] = 0;
        for (int i = 1; i < prices.length; i ++) {
     
            dp[i][0] = Math.max(dp[i - 1][1] + prices[i], dp[i - 1][0]);
            dp[i][1] = Math.max(dp[i - 1][1], -prices[i]);
        }
        return dp[prices.length - 1][0];
    }
}
题目二:122. 买卖股票的最佳时机 II

题解:题目要求可进行多次交易,即k = 无穷大,所以k = k - 1

dp[i][k][0] = max(dp[i-1][k][0], dp[i-1][k][1] + prices[i])
dp[i][k][1] = max(dp[i-1][k][1], dp[i-1][k-1][0] - prices[i])
base case
dp[0][k][0] = 0
dp[0][k][1] = -prices[0]

化简为:

dp[i][0] = max(dp[i-1][0], dp[i-1][1] + prices[i])
dp[i][1] = max(dp[i-1][1], dp[i-1][0] - prices[i])
base case
dp[0][0] = 0
dp[0][1] = -prices[0]

代码如下:

class Solution {
     
    public int maxProfit(int[] prices) {
     
        if (null == prices || 0 == prices.length) {
     
            return 0;
        }
        int[][] dp = new int[prices.length][2];
        // base case
        dp[0][0] = 0;
        dp[0][1] = -prices[0];
        for (int i = 1; i < prices.length; i ++) {
     
            dp[i][0] = Math.max(dp[i - 1][1] + prices[i], dp[i - 1][0]);
            dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] - prices[i]);
        }
        return dp[prices.length - 1][0];
    }
}
题目三:123. 买卖股票的最佳时机 III

题解:考虑k,将k作为一个变量,k = 2。直接套用模板。
代码如下:

class Solution {
     
    public int maxProfit(int[] prices) {
     
        if (null == prices || 0 == prices.length) {
     
            return 0;
        }
        int[][][] dp = new int[prices.length][3][2];
        // base case
        // dp[0][0][0] = 0;
        // dp[0][0][1] = -prices[0];
        // dp[0][1][0] = 0;
        // dp[0][1][1] = -prices[0];
        // dp[0][2][0] = 0;
        // dp[0][2][1] = -prices[0];
        for (int i = 0; i <= 2; i ++) {
     
           dp[0][i][1] = -prices[0];     
        }
        for (int i = 1; i < prices.length; i ++) {
     
            for (int k = 1; k <= 2; k ++) {
     
                dp[i][k][0] = Math.max(dp[i - 1][k][1] + prices[i], dp[i - 1][k][0]);
                dp[i][k][1] = Math.max(dp[i - 1][k][1], dp[i - 1][k - 1][0] - prices[i]);
            }
        }
        return dp[prices.length - 1][2][0];
    }
}
题目四:188. 买卖股票的最佳时机 IV

题解:模板题目
代码如下:

class Solution {
     
    public int maxProfit(int k, int[] prices) {
     
        if (null == prices || 0 == prices.length) {
     
            return 0;
        }
        int[][][] dp = new int[prices.length][k + 1][2];
        // base case
        for (int i = 0; i <= k; i ++) {
     
            dp[0][i][1] = -prices[0];
        }
        for (int i = 1; i < prices.length; i ++) {
     
            for (int j = 1; j <= k; j ++) {
     
                dp[i][j][0] = Math.max(dp[i - 1][j][1] + prices[i], dp[i - 1][j][0]);
                dp[i][j][1] = Math.max(dp[i - 1][j][1], dp[i - 1][j - 1][0] - prices[i]);
            }
        }
        return dp[prices.length - 1][k][0];
    }
}
题目五:309. 最佳买卖股票时机含冷冻期

题解:参考资料
代码如下:

class Solution {
     
    public int maxProfit(int[] prices) {
     
        if (null == prices || 0 == prices.length) {
     
            return 0;
        }
        int[][] dp = new int[prices.length][3];
        // base case
        dp[0][0] = -prices[0];
        dp[0][1] = 0;
        dp[0][2] = 0;
        for (int i = 1; i < prices.length; i ++) {
     
            // 可能状态
            dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1] - prices[i]);
            dp[i][1] = Math.max(dp[i - 1][1],dp[i - 1][2]);
            dp[i][2] = dp[i - 1][0] + prices[i];
        }
        return Math.max(dp[prices.length - 1][1], dp[prices.length - 1][2]);
    }
}
题目六:714. 买卖股票的最佳时机含手续费

题解:考虑手续费,应该在买入股票时减去手续费。k = 无穷大,所以 k = k - 1,所以

dp[i][k][0] = max(dp[i-1][k][0], dp[i-1][k][1] + prices[i])
dp[i][k][1] = max(dp[i-1][k][1], dp[i-1][k-1][0] - prices[i])
base case
dp[0][k][0] = 0
dp[0][k][1] = -prices[0]

化简为:

dp[i][0] = max(dp[i-1][0], dp[i-1][1] + prices[i])
dp[i][1] = max(dp[i-1][1], dp[i-1][0] - prices[i])
base case
dp[0][0] = 0
dp[0][1] = -prices[0]

代码如下:

class Solution {
     
    public int maxProfit(int[] prices, int fee) {
     
        if (null == prices || 0 == prices.length) {
     
            return 0;
        }
        int[][] dp = new int[prices.length][2];
        // 注意:买入要扣除手续费,所以要加入手续费
        dp[0][1] = -(prices[0] + fee);
        dp[0][0] = 0;
        for (int i = 1; i < prices.length; i ++) {
     
            dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] - prices[i] - fee);
            dp[i][0] = Math.max(dp[i - 1][1] + prices[i], dp[i - 1][0]);
        }
        return dp[prices.length - 1][0];
    }
}

2.背包DP

背包DP参考资料都是根据背包九讲文章,题目来源于ACWing刷题网站

2.1 背包系列

题目一:01背包问题(2. 01背包问题)

题解:
[力扣] 动态规划(DP)问题分类汇总_第4张图片
[力扣] 动态规划(DP)问题分类汇总_第5张图片
01背包模板:

for (int i = 1; i <= N; i ++) {
     
           for (int j = V; j >= v[i]; j --) {
     
               dp[j] = Math.max(dp[j],dp[j - v[i]] + w[i]);
           }
       }

AcWing代码如下:

import java.io.*;
import java.util.*;

public class Main {
     
    public static void main(String args[]) throws Exception {
     
       Scanner sc=new Scanner(System.in);
       int N=sc.nextInt(),V=sc.nextInt();
       int[] v = new int[N + 1];
       int[] w = new int[N + 1];
       for (int i = 1; i <= N; i ++) {
     
           v[i] = sc.nextInt();
           w[i] = sc.nextInt();
       }
       int[] dp = new int[V + 1];
       for (int i = 1; i <= N; i ++) {
     
           for (int j = V; j >= v[i]; j --) {
     
               dp[j] = Math.max(dp[j],dp[j - v[i]] + w[i]);
           }
       }
       System.out.println(dp[V]);
       return;
    }
}

494. 目标和 (01背包-求方案数)
题解:
[力扣] 动态规划(DP)问题分类汇总_第6张图片
注意:求方案数不用考虑dp数组初始化,只考虑dp[0]。
代码如下:

class Solution {
     
    public int findTargetSumWays(int[] nums, int S) {
     
        if (null == nums) {
     
            return 0;
        }
        if (0 == nums.length) {
     
            return 1;
        }
        int sum = 0;
        for (int num : nums) {
     
            sum += num;
        }
        // 2sum(p) = sum(nums) + target,所以sum(nums) + target为偶数
        if (sum < Math.abs(S) || (sum + S) % 2 != 0) {
     
            return 0;
        }
        sum = (sum + S) / 2;
        int[] dp = new int[sum + 1];
        // 只考虑dp[0],其他位置初始化不用考虑
        dp[0] = 1;
        // 01背包模板
        for (int num : nums) {
     
            for (int j = sum; j >= num; j --) {
     
                dp[j] += dp[j - num];
            }
        } 
        return dp[sum];
    }
}

416. 分割等和子集 (01背包-要求恰好取到背包容量)
题解:

sum(A) - sum(B) = 0
sum(A) = sum(B)
sum(A) + sum(B) = 2sum(B);
sum(nums) = 2sum(B);
sum(B) = sum(nums) / 2

代码如下:

class Solution {
     
    public boolean canPartition(int[] nums) {
     
        if (null == nums) {
     
            return false;
        }
        int sum = 0;
        for (int num : nums) {
     
            sum += num;
        }
        // sum一定为偶数
        if ((sum & 1) != 0) {
     
            return false;
        }
        // sum = sum / 2
        sum = sum >> 1;
        int[] dp = new int[sum + 1];
        for (int i = 1; i <= sum; i ++) {
     
            dp[i] = Integer.MIN_VALUE;
        }
        // 01背包模板
        dp[0] = 0;
        for (int num : nums) {
     
            for (int j = sum; j >= num; j --) {
     
                dp[j] = Math.max(dp[j], dp[j - num] + 1);
            }
        }
        return dp[sum] > 0 ? true : false;
    }
 }
题目二:完全背包问题(完全背包问题)

题解:
[力扣] 动态规划(DP)问题分类汇总_第7张图片
[力扣] 动态规划(DP)问题分类汇总_第8张图片
[力扣] 动态规划(DP)问题分类汇总_第9张图片
[力扣] 动态规划(DP)问题分类汇总_第10张图片
完全背包模板:

 for (int i = 1; i <= N; i ++) {
     
           // 注意:01背包和完全背包不一样的地方,01背包是从V到v[i](大到小),完全背包是从v[i]到V(小到大)
           for (int j = v[i]; j <=V; j ++) {
     
               dp[j] = Math.max(dp[j], dp[j - v[i]] + w[i]);
           }
       }

AcWing代码如下:

import java.io.*;
import java.util.*;

public class Main {
     
    public static void main(String args[]) throws Exception {
     
       Scanner sc=new Scanner(System.in);
       int N=sc.nextInt(),V=sc.nextInt();
       int[] v = new int[N + 1];
       int[] w = new int[N + 1];
       for (int i = 1; i <= N; i ++) {
     
           v[i] = sc.nextInt();
           w[i] = sc.nextInt();
       }
       int[] dp = new int[V + 1];
       for (int i = 1; i <= N; i ++) {
     
           // 注意:01背包和完全背包不一样的地方,01背包是从V到v[i](大到小),完全背包是从v[i]到V(小到大)
           for (int j = v[i]; j <=V; j ++) {
     
               dp[j] = Math.max(dp[j], dp[j - v[i]] + w[i]);
           }
       }
       System.out.println(dp[V]);
       return;
    }
}

322. 零钱兑换 (完全背包)
题解:

为什么是「完全背包」问题:

1、每个***可以使用无限次;

2***总额有限制;

3、并且具体组合是顺序无关的,还以示例 1 为例:面值总额为 11,方案 [1, 5, 5] 和方案 [5, 1, 5] 视为同一种方案。

但是与「完全」背包问题不一样的地方是:

1、要求恰好填满容积为 amount 的背包,重点是「恰好」、「刚刚好」,而原始的「完全背包」问题只是要求「不超过」;

2、题目问的是总的***数最少,原始的「完全背包」问题让我们求的是总价值最多。

这一点可以认为是:每一个***有一个「占用空间」属性,并且值是固定的,固定值为 11;
作为「占用空间」而言,考虑的最小化是有意义的。
相当于是把「完全背包」问题的「体积」和「价值」属性调换了一下。

因此,这个问题的背景是「完全背包」问题,可以使用「完全背包」问题的解题思路:(「0-1 背包」问题也是这个思路)一个一个去看,一点点扩大考虑的价值的范围(自底向上考虑问题的思想),其实就是在不断地做尝试和比较,实际生活中,人也是这么干的,「盗贼」拿东西也是这样的,看到一个体积小,价值大的东西,就会从背包里把占用地方大,廉价的物品换出来*。

所以代码里:外层循环先遍历的是***面试,内层循环遍历的是面值总和,这是这样写的依据。

本题需要注意的坑:
1.要求的是恰好填满「背包」,所以初始化的时候需要赋值为一个不可能的值:amount + 1。只有在有「正常值」的时候,「状态转移」才可以正常发生。
2.本题的硬币对应背包的价值量为1
3.本题求的是最少种数,即用min

代码如下:

class Solution {
     
    public int coinChange(int[] coins, int amount) {
     
        if (null == coins || 0 == coins.length || amount < 0) {
     
            return -1;
        }
        int[] dp = new int[amount + 1];
        // 不要用Integer.MAX_VALUE,因为Integer.MAX_VALUE + 1会有溢出问题。取一个不可能的数字即可
        for (int i = 1; i <= amount; i ++) {
     
            dp[i] = amount + 1;
        }
        for (int coin : coins) {
     
            for (int j = coin; j <= amount; j ++) {
     
                // 每种硬币对应背包背题的价值量为1
                dp[j] = Math.min(dp[j], dp[j - coin] + 1);
            }
        }
        return dp[amount] == amount + 1 ? -1 : dp[amount];
    }
}

518. 零钱兑换 II (完全背包-求方案数)
代码如下:

class Solution {
     
    public int change(int amount, int[] coins) {
     
        if (0 == amount) {
     
            return 1;
        }
        if (null == coins || 0 == coins.length) {
     
            return 0;
        }    
        int[] dp = new int[amount + 1];
        dp[0] = 1;
        for (int coin : coins) {
     
            for (int j = coin; j <= amount; j ++) {
     
                dp[j] += dp[j - coin];
            }
        }
        return dp[amount];
    }
}
题目三:多重背包问题(多重背包问题 I)

题解:
[力扣] 动态规划(DP)问题分类汇总_第11张图片
[力扣] 动态规划(DP)问题分类汇总_第12张图片
[力扣] 动态规划(DP)问题分类汇总_第13张图片
AcWing代码如下:

import java.io.*;
import java.util.*;
    
public class Main {
     
    
    static class Good{
     
        int v;
        int w;
        Good(int v, int w) {
     
            this.v = v;
            this.w = w;
        }
    }
    
    public static void main(String args[]) throws Exception {
     
       Scanner sc=new Scanner(System.in);
       int N=sc.nextInt(),V=sc.nextInt();
       int v, w, s;
       List<Good> goods = new ArrayList<>();
       int[] dp = new int[V + 1];
       for (int i = 0; i < N; i ++) {
     
           v = sc.nextInt();
           w = sc.nextInt();
           s = sc.nextInt();
           // 将第i种物品转换成01背包中物品,采用二进制分解
           for (int k = 1; k <= s; k *= 2) {
     
               s -= k;
               goods.add(new Good(v * k, w * k));
           }
           if (s > 0) {
     
               goods.add(new Good(v * s, w * s));
           }
       }
       // 01背包
       for (Good good : goods) {
     
           for (int j = V; j >= good.v; j --) {
     
               dp[j] = Math.max(dp[j], dp[j - good.v] + good.w);
           }
       }
       System.out.println(dp[V]);
       return;
    }
}
题目四:混合背包问题(混合背包问题)

题解:
[力扣] 动态规划(DP)问题分类汇总_第14张图片
[力扣] 动态规划(DP)问题分类汇总_第15张图片
多重背包二进制模板:

 
               for (int k = 1; k <= s; k *= 2) {
     
                   s -= k;
                   goods.add(new Good(-1, v * k, w * k));
               }
               if (s > 0) {
     
                   goods.add(new Good(-1, v * s, w * s));
               }

代码如下:

import java.io.*;
import java.util.*;
    
public class Main {
     
    
    static class Good {
     
        int kind;
        int v;
        int w;
        Good(int kind, int v, int w) {
     
            this.kind = kind;
            this.v = v;
            this.w = w;
        }
    }
    public static void main(String args[]) throws Exception {
     
       Scanner sc=new Scanner(System.in);
       int N=sc.nextInt(),V=sc.nextInt();
       int v, w, s;
       List<Good> goods = new ArrayList<>();
       int[] dp = new int[V + 1];
       for (int i = 0; i < N; i ++) {
     
           v = sc.nextInt();
           w = sc.nextInt();
           s = sc.nextInt();
           if (s < 0) {
     
               goods.add(new Good(-1, v, w));
           } else if (s == 0) {
     
               goods.add(new Good(0, v, w));
           } else {
     
               for (int k = 1; k <= s; k *= 2) {
     
                   s -= k;
                   goods.add(new Good(-1, v * k, w * k));
               }
               if (s > 0) {
     
                   goods.add(new Good(-1, v * s, w * s));
               }
           }
       }
       
       for (Good good : goods) {
     
           if (good.kind < 0) {
     
               for (int j = V; j >= good.v; j --) {
     
                   dp[j] = Math.max(dp[j], dp[j - good.v] + good.w);
               }
           } else {
     
               for (int j = good.v; j <= V; j ++) {
     
                   dp[j] = Math.max(dp[j], dp[j - good.v] + good.w);
               }
           }
       }
       System.out.println(dp[V]);
       return;
    }   
}
题目五:二维费用的背包问题

题解:
[力扣] 动态规划(DP)问题分类汇总_第16张图片
[力扣] 动态规划(DP)问题分类汇总_第17张图片
代码如下:

import java.io.*;
import java.util.*;
    
public class Main {
     
    
    public static void main(String args[]) throws Exception {
     
       Scanner sc=new Scanner(System.in);
       int N = sc.nextInt(),V = sc.nextInt(), M = sc.nextInt();
       int v, m,w;
       int[][] dp = new int[V + 1][M + 1];
       for (int i = 0; i < N; i ++) {
     
           v = sc.nextInt();
           m = sc.nextInt();
           w = sc.nextInt();
           for (int j = V; j >= v; j --) {
     
               for (int k = M; k >= m; k --) {
     
                   dp[j][k] = Math.max(dp[j][k], dp[j - v][k - m] + w);
               }
           }
       }
       System.out.println(dp[V][M]);
       return;
    }
}

474. 一和零 (二维费用背包)
题解:将数组里面的字符串看成是物品,每一个字符串都有相应的0和1的个数,即01背包的体积(费用)限制,在这道题里有两个这样的限制,所以用二维dp数组,每一字符串的价值量(01背包的概念)是1。dp数组的初始状态是0.
代码如下:

class Solution {
     
    public int findMaxForm(String[] strs, int m, int n) {
     
        if (null == strs) {
     
            return 0;
        }
        int[][] dp = new int[m + 1][n + 1];
        // 01背包模板
        dp[0][0] = 0;
        for (String str : strs) {
     
            // 费用限制
            int zeroNum = numZeroAndOne(str)[0];
            int oneNum = numZeroAndOne(str)[1];
            for (int j = m; j >= zeroNum; j --) {
     
                for (int k = n; k >= oneNum; k --) {
     
                    dp[j][k] = Math.max(dp[j][k], dp[j - zeroNum][k - oneNum] + 1);
                }
            }
        }
        return dp[m][n];
    }
    // 计算一个字符串的0和1的各自的数量
    private int[] numZeroAndOne(String str) {
     
        int[] res = new int[2];
        for (char c : str.toCharArray()) {
     
            res[c - '0'] ++;
        }
        return res;
    }
}
题目六:分组背包问题(分组背包问题)

题解:
[力扣] 动态规划(DP)问题分类汇总_第18张图片
代码如下:

import java.io.*;
import java.util.*;
    
public class Main {
     
    
    public static void main(String args[]) throws Exception {
     
       Scanner sc=new Scanner(System.in);
       int N = sc.nextInt(),V = sc.nextInt();
       int s;
       int[] v = new int[110];
       int[] w = new int[110];
       int[] dp = new int[V + 1];
       for (int i = 0; i < N; i ++) {
     
           s = sc.nextInt();
           for (int j = 0; j < s; j ++) {
     
              v[j] = sc.nextInt();
              w[j] = sc.nextInt();
           }
           for (int j = V; j > 0; j --) {
     
               for (int k = 0; k < s; k ++) {
     
                   if (j >= v[k]) {
     
                       dp[j] = Math.max(dp[j], dp[j - v[k]] + w[k]);
                   }
               }
           }
       }
       System.out.println(dp[V]);
       return;
    }
}

你可能感兴趣的:(leetCode,算法)