《算法题讲解指南:动态规划算法--简单多状态dp问题》--13.删除并获得点数,14.粉刷房子

🔥小叶-duck个人主页

❄️个人专栏《Data-Structure-Learning》《C++入门到进阶&自我学习过程记录》
《算法题讲解指南》--优选算法
《算法题讲解指南》--递归、搜索与回溯算法
《算法题讲解指南》--动态规划算法

未择之路,不须回头
已择之路,纵是荆棘遍野,亦作花海遨游


目录

13.删除并获得点数

题目链接:

题目描述:

题目示例:

解法(动态规划):

算法思路:

C++算法代码:

算法总结及流程解析:

14.粉刷房子

题目链接:

题目描述:

题目示例:

解法(动态规划):

算法思路:

C++算法代码:

算法总结及流程解析:

结束语


13.删除并获得点数

题目链接:

740. 删除并获得点数 - 力扣(LeetCode)

题目描述:

题目示例:

解法(动态规划):

算法思路:

其实这道题依旧是「打家劫舍」问题的变型。

我们注意到题目描述,选择 x 数字的时候,x-1 与 x+1 是不能被选择的。像不像「打家劫舍」问题中,选择 i 位置的金额之后,就不能选择 i - 1 位置以及 i + 1 位置的金额呢?

因此,我们可以创建一个大小为 10001 (根据题目的数据范围)的 hash 数组,将 nums 数组中每一个元素 x,累加到 hash 数组下标为 x 的位置处,然后在 hash 数组上来一次「打家劫舍」即可。

C++算法代码:

cpp 复制代码
class Solution {
public:
    int deleteAndEarn(vector<int>& nums) 
    {
        //统计每个数字出现的次数,放到一个数组中
        int arr[10001] = { 0 };
        for(int i = 0; i < nums.size(); i++)
        {
            arr[nums[i]]++;
        }   

        vector<int> f(10001);//f[i]表示在arr中第i个位置选择删除并获得点数,此时获得的最大点数
        vector<int> g(10001);//g[i]表示在arr中第i个位置不选择删除并获得点数,此时获得的最大点数
        f[1] = arr[1] * 1;
        for(int i = 2; i < 10001; i++)
        {
            f[i] = g[i - 1] + arr[i] * i;
            g[i] = max(f[i - 1], g[i - 1]);
        }
        return max(f[10000], g[10000]);
    }
};

算法总结及流程解析:

14.粉刷房子

题目链接:

LCR 091. 粉刷房子 - 力扣(LeetCode)

题目描述:

题目示例:

解法(动态规划):

算法思路:

1.状态表示:

对于线性dp,我们可以用「经验+题目要求」来定义状态表示:

i.以某个位置为结尾,巴拉巴拉;

ii.以某个位置为起点,巴拉巴拉。

这里我们选择比较常用的方式,以某个位置为结尾,结合题目要求,定义一个状态表示:

但是我们这个题在i位置的时候,会面临「红」「蓝」「绿」三种抉择,所依赖的状态需要细

分:

dpi0表示:粉刷到i位置的时候,最后一个位置粉刷上「红色」,此时的最小花费;

dpi1表示:粉刷到i位置的时候,最后一个位置粉刷上「蓝色」,此时的最小花费;

dpi2表示:粉刷到i位置的时候,最后一个位置粉刷上「绿色」,此时的最小花费。

2.状态转移方程:

因为状态表示定义了三个,因此我们的状态转移方程也要分析三个:

对于dpi0

如果第i个位置粉刷上「红色」,那么i-1位置上可以是「蓝色」或者「绿色」。因此我们需要知道粉刷到i-1位置上的时候,粉刷上「蓝色」或者「绿色」的最小花费,然后加上i位置的花费即可。于是状态转移方程为:dpi0= min(dpi - 11,dpi- 12) + costsi - 10;

同理,我们可以推导出另外两个状态转移方程为:

dpi1 = min(dpi - 10, dpi - 12) + costsi - 11;

dpi2 = min(dpi - 10, dpi - 11) + costsi - 12

3.初始化:

可以在最前面加上一个「辅助结点」,帮助我们初始化。使用这种技巧要注意两个点:

i.辅助结点里面的值要「保证后续填表是正确的」;

ii.「下标的映射关系」。

在本题中,添加一个节点,并且初始化为0即可。

4.填表顺序

根据「状态转移方程」得「从左往右,三个表一起填」。

5.返回值

根据「状态表示」,应该返回最后一个位置粉刷上三种颜色情况下的最小值,因此需要返回:

min(dpn0, min(dpn1, dpn2)) 。

C++算法代码:

cpp 复制代码
class Solution {
public:
    int minCost(vector<vector<int>>& costs) 
    {
        // //方法一:用三个一维dp数组实现动态规划:
        // int n = costs.size();
        // vector<int> red(n);
        // vector<int> blue(n);
        // vector<int> green(n);
        // red[0] = costs[0][0];
        // blue[0] = costs[0][1];
        // green[0] = costs[0][2];
        // for(int i = 1; i < n; i++)
        // {
        //     red[i] = min(blue[i - 1], green[i - 1]) + costs[i][0];
        //     blue[i] = min(red[i - 1], green[i - 1]) + costs[i][1];
        //     green[i] = min(red[i - 1], blue[i - 1]) + costs[i][2];
        // }
        // return min(min(red[n - 1], blue[n - 1]), green[n - 1]);

        //方法二:用一个二维dp数组实现动态规划:
        int n = costs.size();
        vector<vector<int>> dp(n, vector<int>(3));
        dp[0][0] = costs[0][0];
        dp[0][1] = costs[0][1];
        dp[0][2] = costs[0][2];
        for(int i = 1; i < n; i++)
        {
            dp[i][0] = min(dp[i - 1][1], dp[i - 1][2]) + costs[i][0];
            dp[i][1] = min(dp[i - 1][0], dp[i - 1][2]) + costs[i][1];
            dp[i][2] = min(dp[i - 1][0], dp[i - 1][1]) + costs[i][2];
        }
        return min(min(dp[n - 1][0], dp[n - 1][1]), dp[n - 1][2]);
    }
};

算法总结及流程解析:

结束语

到此,13.删除并获得点数,14.粉刷房子 这两道算法题就讲解完了。**删除并获得点数,通过构建hash数组转化为打家劫舍问题,定义fi和gi分别表示选择/不选i位置时的最大点数,状态转移后取最大值。粉刷房子,建立dpi0-2表示i位置刷红/蓝/绿的最小花费,通过比较前一个位置其他颜色的最小花费加上当前成本来更新状态,最终返回三种颜色的最小花费。**希望大家能有所收获!

相关推荐
水上冰石4 分钟前
comfui的sd1.5模型,有多少采样算法,详解每一个采样算法
人工智能·算法
磊 子15 分钟前
STL之deque和list以及两者与vector的对比
开发语言·c++·list
郝学胜_神的一滴19 分钟前
CMake 012:Linux 下动态库与可执行程序的单文件构建
c++·cmake
黎阳之光22 分钟前
视频孪生+空天地水工融合,黎阳之光构建智慧水利监测新范式
大数据·人工智能·物联网·算法·安全
小poop28 分钟前
操作符详解:从入门到精通
c++
山上三树31 分钟前
C/C++ 高频报错速查表(开发通用版)
c语言·开发语言·c++
cheems952734 分钟前
[算法手记] 贪心 爬楼梯问题
算法·贪心算法
Tian_Hang38 分钟前
Factory Method | 工厂方法
开发语言·c++
KaMeidebaby1 小时前
卡梅德生物技术快报|酵母双杂交 cDNA 文库构建与蛋白互作筛选流程
服务器·前端·数据库·人工智能·算法
sheeta19981 小时前
LeetCode 每日一题笔记 日期:2026.05.27 题目:3121. 统计特殊字母的数量 II
笔记·算法·leetcode