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

文章目录

一. 力扣 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];
    }
}
相关推荐
longlongzihan28 分钟前
LeetCode 24.两两交换链表中的节点:虚拟头结点与指针
算法·leetcode·链表
residual_fan29 分钟前
基于控制感知域对抗网络的变工况故障诊断:从控制系统与运行状态协同的角度建立模型
人工智能·算法·数据挖掘·数据分析
翻山越岭的少年35 分钟前
用控制信号理解状态变化:基于控制感知域对抗网络的变工况故障诊断
算法
longlongzihan1 小时前
从LeetCode 19. 删除链表的倒数第 N 个结点深入理解“哨兵节点”
c++·算法·leetcode·链表
DeroZan1 小时前
# jieba 分词 & 文本语料分析 & Python 内置函数笔记
算法
Gigavision1 小时前
CAS(ME)²数据集 感知图卷积网络算法 CAS(ME)²数据集下载
网络·算法
杜 硕1 小时前
快速排序02
算法·排序算法
careathers1 小时前
【数据结构】二叉树拓展
数据结构·算法
java_nnnn2 小时前
LeetCode刷题滑动窗口(长度最小的子数组)
算法·leetcode·职场和发展
@atweiwei2 小时前
训练 AI 大模型系列之 LoRA:不动模型本体,靠一条低秩旁路改专长(附完整手算算例)
人工智能·算法·ai·语言模型·rag