当前位置: 首页 > news >正文

[Algorithm][动态规划][简单多状态DP问题][按摩师][打家劫舍Ⅱ][删除并获得点数][粉刷房子]详细讲解

目录

  • 1.按摩师
    • 1.题目链接
    • 2.算法思路详解
    • 3.代码实现
  • 2.打家劫舍 II
    • 1.题目链接
    • 2.算法思路详解
    • 3.代码实现
  • 3.删除并获得点数
    • 1.题目链接
    • 2.算法思路详解
    • 3.代码实现
  • 4.粉刷房子
    • 1.题目链接
    • 2.算法思路详解
    • 3.代码实现


1.按摩师

1.题目链接

  • 按摩师

2.算法思路详解

  • 思路
    • 确定状态表示 -> dp[i]的含义

      • 选择到i位置的时候,此时的最长预约时长
      • 本题,状态表示还可以继续细分:
        • f[i]:选择到i位置的时候,nums[i]必选,此时的最长预约时长
        • g[i]:选择到i位置的时候,nums[i]不选,此时的最长预约时长
    • 推导状态转移方程

      • f[i] = g[i - 1] + nums[i]
      • g[i] = max(f[i - 1], g[i - 1])
        请添加图片描述
    • 初始化:f[0] = nums[0], g[0] = 0

    • 确定填表顺序:从左往右,两个表一起填

    • 确定返回值:max(f[n - 1], g[n - 1])


3.代码实现

int massage(vector<int>& nums) 
{int n = nums.size();if(n == 0) return 0;vector<int> f(n);vector<int> g(n);f[0] = nums[0];for(int i = 1; i < n; i++){f[i] = g[i - 1] + nums[i];g[i] = max(f[i - 1], g[i - 1]);}return max(f[n - 1], g[n - 1]);
}

2.打家劫舍 II

1.题目链接

  • 打家劫舍 II

2.算法思路详解

  • 思路解析:本题比打家劫舍Ⅰ只多了环形问题,那么只需将环形问题分类讨论(依据nums[0]),拆解为两个线性的打家劫舍Ⅰ问题即可
    • 第一个位置偷nums[0] + _rob[2, n - 2] <— 第二个位置和最后一个位置不偷
    • 第一个位置不偷_rob(1, n - 1) <— 偷第二个位置和最后一个位置
  • 思路
    • 确定状态表示 -> dp[i]的含义

      • i位置的时候,此时的最大金额
      • 本题,状态表示还可以继续细分:
        • f[i]:偷到i位置的时候,nums[i]必偷,此时的最大金额
        • g[i]:偷到i位置的时候,nums[i]不偷,此时的最大金额
    • 推导状态转移方程

      • f[i] = g[i - 1] + nums[i]
      • g[i] = max(f[i - 1], g[i - 1])
        请添加图片描述
    • 初始化:f[0] = nums[0], g[0] = 0

    • 确定填表顺序:从左往右,两个表一起填

    • 确定返回值:max(f[n - 1], g[n - 1])


3.代码实现

class Solution
{
public:int rob(vector<int>& nums) {int n = nums.size();// 分类讨论,取两种情况中的最大值return max(nums[0] + _rob(nums, 2, n - 2), _rob(nums, 1, n - 1));}int _rob(vector<int>& nums, int left, int right){if(left > right) return 0;int n = nums.size();vector<int> f(n); // 选vector<int> g(n); // 不选f[left] = nums[left];for(int i = left + 1; i <= right; i++){f[i] = g[i - 1] + nums[i];g[i] = max(f[i - 1], g[i - 1]);}return max(f[right], g[right]);}
};

3.删除并获得点数

1.题目链接

  • 删除并获得点数

2.算法思路详解

  • 思路解析:本题可以先做一个预处理,将问题转化为打家劫舍

    • 思路
      • 打家劫舍要求访问数组中的数的顺序是连续的,但本题原始数组显然不符合要求
      • 虽然原始数组数值不符合要求,但是经过转换,数组下标是可以符合顺序连续的
    • 做法
      • 将原始数组中的数,统计到arr,然后在arr中,做一次打家劫舍问题即可
      • 此时,数值相同的值的和可以被其本身值作为arr的下标索引到 <— hash[x] = sum(x)
      • arr[i]i这个数出现的总和
        请添加图片描述
  • 思路

    • 确定状态表示 -> dp[i]的含义

      • i位置的时候,此时获得的最大点数
      • 本题,状态表示还可以继续细分:
        • f[i]:选到i位置的时候,nums[i]必选,此时获得的最大点数
        • g[i]:选到i位置的时候,nums[i]不选,此时获得的最大点数
    • 推导状态转移方程

      • f[i] = g[i - 1] + arr[i]
      • g[i] = max(f[i - 1], g[i - 1])
        请添加图片描述
    • 初始化:f[0] = arr[0], g[0] = 0

    • 确定填表顺序:从左往右,两个表一起填

    • 确定返回值:max(f[n], g[n])


3.代码实现

int deleteAndEarn(vector<int>& nums) 
{sort(nums.begin(), nums.end());int n = nums.back(); // maxvector<int> arr(n + 1);for(auto& x : nums){arr[x] += x;}vector<int> f(n + 1);vector<int> g(n + 1);for(int i = 1; i <= n; i++){f[i] = g[i - 1] + arr[i];g[i] = max(f[i - 1], g[i - 1]);}return max(f[n], g[n]);
}

4.粉刷房子

1.题目链接

  • 粉刷房子

2.算法思路详解

  • 思路
    • 确定状态表示 -> dp[i][j]的含义:i -> 到了哪个位置,j -> 这个位置的哪个颜色

      • dp[i][0]:粉刷i位置的时候,最后一个位置刷上红色,此时的最小花费
      • dp[i][1]:粉刷i位置的时候,最后一个位置刷上蓝色,此时的最小花费
      • dp[i][2]:粉刷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]
        请添加图片描述
    • 初始化:dp[0][0] = dp[0][1] = dp[0][2] = 0

    • 确定填表顺序:从左往右,一次填写三个表

    • 确定返回值:min(dp[n][0], min(dp[n][1], dp[n][2]))


3.代码实现

int minCost(vector<vector<int>>& costs) 
{int n = costs.size();vector<vector<int>> dp(n + 1, vector<int>(3));for(int i = 1; i <= n; 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];}return min(dp[n][0], min(dp[n][1], dp[n][2]));
}

相关文章:

  • 手机相册的照片彻底删除了怎么恢复?删除照片恢复的5种方法
  • 甘肃教育杂志社-甘肃教育编辑部
  • CSP俄罗斯方块(简单易懂)
  • C语言笔记21 •模拟atoi函数•
  • conda常见命令
  • 汽车R155法规中,汽车获取到的VTA证书,E后面的数字表示什么意思?
  • MySQL入门学习-查询进阶.别名
  • 携手AI,如何共赢未来?
  • java string类
  • 每日力扣刷题day05(小白简单题)
  • Python游戏编程:一步步用Python打造经典贪吃蛇小游戏
  • 知能行——考研数学利器
  • 牛马真的沉默了,入职第一天就干活
  • 梦幻西游手游挂机脚本,搬砖挂机赚米项目,号称单窗口日收益60+(教程+软件)
  • Python | Leetcode Python题解之第101题对称二叉树
  • (十五)java多线程之并发集合ArrayBlockingQueue
  • @angular/forms 源码解析之双向绑定
  • Java 23种设计模式 之单例模式 7种实现方式
  • LeetCode算法系列_0891_子序列宽度之和
  • Vue--数据传输
  • webpack4 一点通
  • 动手做个聊天室,前端工程师百无聊赖的人生
  • 对JS继承的一点思考
  • 三分钟教你同步 Visual Studio Code 设置
  • 双管齐下,VMware的容器新战略
  • 我看到的前端
  • 移动端 h5开发相关内容总结(三)
  • 正则表达式小结
  • ​Kaggle X光肺炎检测比赛第二名方案解析 | CVPR 2020 Workshop
  • #android不同版本废弃api,新api。
  • #QT(一种朴素的计算器实现方法)
  • (12)Linux 常见的三种进程状态
  • (ctrl.obj) : error LNK2038: 检测到“RuntimeLibrary”的不匹配项: 值“MDd_DynamicDebug”不匹配值“
  • (js)循环条件满足时终止循环
  • (LeetCode) T14. Longest Common Prefix
  • (Redis使用系列) Springboot 使用redis实现接口幂等性拦截 十一
  • (苍穹外卖)day03菜品管理
  • (六)vue-router+UI组件库
  • (四)汇编语言——简单程序
  • (心得)获取一个数二进制序列中所有的偶数位和奇数位, 分别输出二进制序列。
  • .“空心村”成因分析及解决对策122344
  • .bat批处理(五):遍历指定目录下资源文件并更新
  • .JPG图片,各种压缩率下的文件尺寸
  • .libPaths()设置包加载目录
  • .net core使用ef 6
  • .net websocket 获取http登录的用户_如何解密浏览器的登录密码?获取浏览器内用户信息?...
  • .NET 应用启用与禁用自动生成绑定重定向 (bindingRedirect),解决不同版本 dll 的依赖问题
  • .NET应用架构设计:原则、模式与实践 目录预览
  • .NET中 MVC 工厂模式浅析
  • .Net组件程序设计之线程、并发管理(一)
  • .pings勒索病毒的威胁:如何应对.pings勒索病毒的突袭?
  • @ConditionalOnProperty注解使用说明
  • @LoadBalanced 和 @RefreshScope 同时使用,负载均衡失效分析
  • @Repository 注解
  • @RequestMapping-占位符映射