算法奇妙屋(二十四)-二维费用的背包问题、似包非包问题、卡特兰数问题(动态规划)

文章目录

一. 力扣 474. 一和零

1. 题目解析

我们的第一道二维费用的背包问题模板, 这里我们会在题目解析来梳理什么是二维费用

2. 算法原理

和01背包问题很相似

3. 代码

java 复制代码
class Solution {
    public int findMaxForm(String[] strs, int m, int n) {
        int len = strs.length;
        int[][][] dp = new int[len + 1][m + 1][n + 1];
        for (int i = 1; i <= len; i++) {
            int a = 0;
            int b = 0;
            for (char ch : strs[i - 1].toCharArray()) {
                if (ch == '0') {
                    a++;
                } else {
                    b++;
                }
            }
            for (int j = 0; j <= m; j++) {
                for (int k = 0; k <= n; k++) {
                    dp[i][j][k] = dp[i - 1][j][k];

                    if (j >= a && k >= b) {
                        dp[i][j][k] = Math.max(dp[i][j][k], dp[i - 1][j - a][k - b] + 1);
                    }
                }
            }
        }
        return dp[len][m][n];
    }
}

4. 优化

这道题和01背包的优化原理也基本一致, 直接摘抄01背包的优化原理

5. 优化后的代码

删除第一维度, j 和 k的遍历顺序颠倒, 范围缩小

java 复制代码
class Solution {
    public int findMaxForm(String[] strs, int m, int n) {
        int len = strs.length;
        int[][] dp = new int[m + 1][n + 1];
        for (int i = 1; i <= len; i++) {
            int a = 0;
            int b = 0;
            for (char ch : strs[i - 1].toCharArray()) {
                if (ch == '0') {
                    a++;
                } else {
                    b++;
                }
            }
            for (int j = m; j >= a; j--) {
                for (int k = n; k >= b; k--) {
                    dp[j][k] = Math.max(dp[j][k], dp[j - a][k - b] + 1);
                }
            }
        }
        return dp[m][n];
    }
}

二. 力扣 879. 盈利计划

1. 题目解析

题目较难理解, 这里主要是讲解题目含义

2. 算法原理

3. 代码

java 复制代码
class Solution {
    public int profitableSchemes(int n, int minProfit, int[] group, int[] profit) {
        // 建表
        int len = group.length;
        int[][][] dp = new int[len + 1][n + 1][minProfit + 1];
        int mod = (int)1e9 + 7;
        // 初始化
        for (int j = 0; j <= n; j++) {
            dp[0][j][0] = 1;
        }
        // 填表
        for (int i = 1; i <= len; i++) {
            for (int j = 0; j <= n; j++) {
                for (int k = 0; k <= minProfit; k++) {
                    dp[i][j][k] = dp[i - 1][j][k] % mod;
                    if (j >= group[i - 1]) {
                        dp[i][j][k] = (dp[i][j][k] + dp[i - 1][j - group[i - 1]][Math.max(0, k - profit[i - 1])]) % mod;
                    }
                }
            }
        }
        // 返回结果
        return dp[len][n][minProfit];
    }
}

4. 优化后的代码

删除第一维度, j 和 k的遍历顺序颠倒, 范围缩小

java 复制代码
class Solution {
    public int profitableSchemes(int n, int minProfit, int[] group, int[] profit) {
        // 建表
        int len = group.length;
        int[][] dp = new int[n + 1][minProfit + 1];
        int mod = (int) 1e9 + 7;
        // 初始化
        for (int j = 0; j <= n; j++) {
            dp[j][0] = 1;
        }
        // 填表
        for (int i = 1; i <= len; i++) {
            for (int j = n; j >= group[i - 1]; j--) {
                for (int k = minProfit; k >= 0; k--) {
                    dp[j][k] = (dp[j][k] + dp[j - group[i - 1]][Math.max(0, k - profit[i - 1])]) % mod;
                }
            }
        }
        // 返回结果
        return dp[n][minProfit];
    }
}

三. (似包非包问题) 力扣 377. 组合总和 Ⅳ

1. 题目解析

注意理解题意, 说的是组合, 但其实求得是排列

2. 算法原理

像背包问题, 但其实不是背包问题, 用原始的归纳来解决

3. 代码

java 复制代码
class Solution {
    public int combinationSum4(int[] nums, int target) {
        // 建表
        int n = nums.length;
        int[] dp = new int[target + 1];
        // 初始化
        dp[0] = 1;
        // 填表
        for (int i = 1; i <= target; i++) {
            for (int j = 0; j < n; j++) {
                if (i >= nums[j]) {
                    dp[i] += dp[i - nums[j]];
                }
            }
        }
        // 返回值
        return dp[target];
    }
}

四. (卡特兰数) 力扣 96. 不同的二叉搜索树

1. 题目解析

重点是理解什么是二叉搜索树

2. 算法原理

3. 代码

java 复制代码
class Solution {
    public int numTrees(int n) {
        // 建表
        int[] dp = new int[n + 1];
        // 初始化
        dp[0] = 1;
        // 填表
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= i; j++) {
                dp[i] += dp[j - 1] * dp[i - j];
            }
        }
        // 返回值
        return dp[n];
    }
}
相关推荐
CoderCodingNo4 小时前
【GESP】C++五级练习题 luogu-P1865 A % B Problem
开发语言·c++·算法
大闲在人4 小时前
7. 供应链与制造过程术语:“周期时间”
算法·供应链管理·智能制造·工业工程
小熳芋4 小时前
443. 压缩字符串-python-双指针
算法
2501_924878734 小时前
数据智能驱动进化:AdAgent 多触点归因与自我学习机制详解
人工智能·逻辑回归·动态规划
Charlie_lll4 小时前
力扣解题-移动零
后端·算法·leetcode
chaser&upper4 小时前
矩阵革命:在 AtomGit 解码 CANN ops-nn 如何构建 AIGC 的“线性基石”
程序人生·算法
weixin_499771554 小时前
C++中的组合模式
开发语言·c++·算法
iAkuya5 小时前
(leetcode)力扣100 62N皇后问题 (普通回溯(使用set存储),位运算回溯)
算法·leetcode·职场和发展
近津薪荼5 小时前
dfs专题5——(二叉搜索树中第 K 小的元素)
c++·学习·算法·深度优先
xiaoye-duck5 小时前
吃透 C++ STL list:从基础使用到特性对比,解锁链表容器高效用法
c++·算法·stl