《算法题讲解指南:动态规划算法--简单多状态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位置刷红/蓝/绿的最小花费,通过比较前一个位置其他颜色的最小花费加上当前成本来更新状态,最终返回三种颜色的最小花费。**希望大家能有所收获!

相关推荐
老鼠只爱大米1 小时前
LeetCode经典算法面试题 #347:前 K 个高频元素(最小堆、桶排序、快速选择等多种实现方案详解)
算法·leetcode·堆排序·java面试题·桶排序·快速选择·topk
2401_831824962 小时前
内存泄漏检测与防范
开发语言·c++·算法
FluxMelodySun2 小时前
机器学习(二十五) 降维:主成分分析(PCA)及特征值分解
人工智能·算法·机器学习
liuyao_xianhui2 小时前
优选算法_分治_快速排序_归并排序_C++
开发语言·数据结构·c++·算法·leetcode·排序算法·动态规划
爱丽_3 小时前
ThreadLocal 机制:弱引用 Entry、内存泄漏、线程池复用与线上排查
java·jvm·算法
2301_815482933 小时前
C++编译期矩阵运算
开发语言·c++·算法
liulilittle3 小时前
LINUX RING BUFFER TUN/TAP 1
linux·服务器·网络·c++·信息与通信·通信
☆5663 小时前
C++中的类型擦除技术
开发语言·c++·算法
m0_569881473 小时前
C++与自动驾驶系统
开发语言·c++·算法