《算法题讲解指南:动态规划算法--简单多状态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位置的时候,会面临「红」「蓝」「绿」三种抉择,所依赖的状态需要细

分:

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

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

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

2.状态转移方程:

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

对于dp[i][0]:

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

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

dp[i][1] = min(dp[i - 1][0], dp[i - 1][2]) + costs[i - 1][1];

dp[i][2] = min(dp[i - 1][0], dp[i - 1][1]) + costs[i - 1][2]。

3.初始化:

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

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

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

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

4.填表顺序

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

5.返回值

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

min(dp[n][0], min(dp[n][1], dp[n][2])) 。

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数组转化为打家劫舍问题,定义f[i]和g[i]分别表示选择/不选i位置时的最大点数,状态转移后取最大值。粉刷房子,建立dp[i][0-2]表示i位置刷红/蓝/绿的最小花费,通过比较前一个位置其他颜色的最小花费加上当前成本来更新状态,最终返回三种颜色的最小花费。**希望大家能有所收获!

相关推荐
AI进化营-智能译站几秒前
ROS2 C++开发系列19-枚举定义机器人状态机|随机数生成仿真测试数据流
java·c++·ai·机器人
迷途之人不知返8 分钟前
深入讨论模板
c++
AI进化营-智能译站18 分钟前
ROS2 C++开发系列18-STL容器实战:deque缓存激光雷达数据|priority_queue调度任务
开发语言·c++·缓存·ai
ulias21220 分钟前
leetcode热题 - 5
数据结构·算法·leetcode
Funny_AI_LAB30 分钟前
Naval最新播客谈“氛围编码”:Vibe Coding 开启“一人独角兽”时代
人工智能·算法·语言模型·agi
如何原谅奋力过但无声31 分钟前
【灵神高频面试题合集04-05】二分查找
数据结构·python·算法·leetcode
hehelm32 分钟前
C++11 新特性
c++
我不是懒洋洋34 分钟前
【数据结构】排序算法(直接插入排序、希尔排序、选择排序、堆排序、冒泡排序、快速排序、归并排序、计数排序)
c语言·数据结构·c++·经验分享·算法·排序算法
MediaTea35 分钟前
ML:逻辑回归的基本原理与实现
人工智能·算法·机器学习·数据挖掘·逻辑回归
邪修king37 分钟前
UE5:C++ 实现 游戏逻辑 ↔ UI 双向联动
c++·游戏·ue5