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

【动态规划】打家劫舍类问题

一、按摩师

17.16. 按摩师

题目描述:

题目分析:

1、状态表示

每个预约都只会有两种选择,即选或不选。因此我们可以用 

  • dp[i][0] 表示不选择第 i 个预约时,最长的预约时长
  • dp[i][1] 表示选择第 i 个预约时,最长的预约时长

2、状态转移方程

对于 dp[i][0] :

  • 如果我们选择了第 i 个预约,那么第  i-1 次预约就一定不会选择,这时我们只需要知道不选第 i-1 次预约时的最长预约时长即可,即 dp[i-1][0] 的值,再加上 num[i]  即可。可得递推公式就为:

        dp[i][1]=dp[i-1][0]+nums[i]

对于 dp[i][1] :

  • 如果我们不选择第 i 个预约,那么第  i-1 次预约就可以被选择,当然也可以不选,这时我们只需要知道选或不选第 i-1 次预约时分别的最长预约时长即可,即 dp[i-1][0] 与 dp[i-1][0] 的值,取这两个中的最大值即可。可得递推公式就为:

       dp[i][0]=Math.max(dp[i-1][1],dp[i-1][0])

3、初始化

为了避免 i-1 时越界,我们初始化dp表的长度为 n+1,然后从 i=1 开始遍历

要注意下标的映射关系,此时 nums[i-1] 表示nums中第 i 个元素

4、返回值

直接返回 Math.max(dp[n][0],dp[n][1]),因为我们不确定最后一个选不选。

代码实现:

class Solution {
    public int massage(int[] nums) {
        int n=nums.length;
        int[][] dp=new int[n+1][2];
        for(int i=1;i<=n;i++){
            dp[i][0]=Math.max(dp[i-1][1],dp[i-1][0]);
            dp[i][1]=dp[i-1][0]+nums[i-1];
        }
        return Math.max(dp[n][0],dp[n][1]);
    }
}

二、打家劫舍 II

213. 打家劫舍 II

题目描述:

题目分析:

其实这就是在上题的基础上做了一些限制。我们可以根据第一号房子是否选择来将问题抽象成两个模型:

  • 偷第一号房子:此能就不能去偷第二号房子与第n号房子,就是还能偷 [3,n-1] 区间内的房子
  • 不偷第一号房子:此时可以偷最后一个房子,也就是说可以偷 [2,n] 区间内的房子

我们可以将上题中的 “打家劫舍” 模型抽象出来,将求取 [1,n] 范围内的最优选改为设定的 [l,r] 范围内的最优选。只需要修改一下遍历时的边界即可

此时就将该问题抽象成了两个 “打家劫舍” 问题的最优解了。

代码实现:

class Solution {
    public int rob(int[] nums) {
        int n=nums.length;
        return Math.max(nums[0]+fun(nums,3,n-1),fun(nums,2,n));
    }
    public static int fun(int[] nums,int l,int r){
        int[][] dp=new int[nums.length+1][2];
        for(int i=l;i<=r;i++){
            dp[i][0]=Math.max(dp[i-1][0],dp[i-1][1]);
            dp[i][1]=dp[i-1][0]+nums[i-1];
        }
        return Math.max(dp[r][0],dp[r][1]);
    }
    
}

三、删除并获得点数

740. 删除并获得点数

题目描述:

题目分析:

这题看上去似乎与 “打家劫舍” 毫不相关。但仔细观察我们会发现,当选择值为 num[i] 的数字时, num[i] -1与 num[i] +1就无法被选中了。这与不能连续选择元素的 “打家劫舍” 问题不谋而合

我们可以创建一个hash数组,将 num[i] 的值映射到 hash数组对应的下标。然后再对hash数组进行一次 “打家劫舍” 即可

代码实现:

class Solution {
    public int deleteAndEarn(int[] nums) {
        int[] arr=new int[10001];
        for(int num:nums){
            arr[num]+=num;
        }
        int[] f=new int[10001],g=new int[10001];
        f[0]=arr[0];
        for(int i=1;i<10001;i++){
            f[i]=g[i-1]+arr[i];
            g[i]=Math.max(f[i-1],g[i-1]);
        }
        return Math.max(f[10000],g[10000]);
    }
}

四、粉刷房子

LCR 091. 粉刷房子

题目描述:

题目分析:

这个问题其实就是拓展版的 “打家劫舍” 问题。普通的 “打家劫舍” 问题每个状态只有 选与不选 两种,而该题有三种。但其实万变不离其中,仔细分析每种状态也能很好地做出来。

1、状态表示

  • 用 r[i] 表示第 i 个位置选择红色时的最小花费
  • 用 b[i] 表示第 i 个位置选择篮色时的最小花费
  • 用 g[i] 表示第 i 个位置选择绿色时的最小花费

2、状态转移方程

由于每个位置都有三种选择,也就对应了三种状态:

对于 r[i] :

  • 如果第 i 个位置刷上红色,那么第 i-1 个位置上就只能刷 蓝色或绿色。因此我们只需要知道第 i-1 个位置刷上 蓝色或绿色 这两种情况中的最小花费,再加上 i 位置的花费即可。可得状态转移方程就为:

        r[i]=Math.min(b[i-1],g[i-1])+costs[i][0]

同理可以得出另外两种状态转移方程为:

        b[i]=Math.min(r[i-1],g[i-1])+costs[i][1]
        g[i]=Math.min(r[i-1],b[i-1])+costs[i][2]

4、初始化

为了避免 i-1 发生越界访问,我们可以先初始化当 i=0 时每种情况的初始值。而由于是首次选择,因此每组的最小花费就应该为对应的costs本身:

        r[0]=costs[0][0]
        b[0]=costs[0][1]
        g[0]=costs[0][2]

代码实现:

class Solution {
    public int minCost(int[][] costs) {
        int n=costs.length;
        int[] r=new int[n],b=new int[n],g=new int[n];
        r[0]=costs[0][0];
        b[0]=costs[0][1];
        g[0]=costs[0][2];
        for(int i=1;i<n;i++){
            r[i]=Math.min(b[i-1],g[i-1])+costs[i][0];
            b[i]=Math.min(r[i-1],g[i-1])+costs[i][1];
            g[i]=Math.min(r[i-1],b[i-1])+costs[i][2];
        }
        return Math.min(r[n-1],Math.min(b[n-1],g[n-1]));
    }
}


那么本篇文章就到此为止了,如果觉得这篇文章对你有帮助的话,可以点一下关注和点赞来支持作者哦。如果有什么讲的不对的地方欢迎在评论区指出,希望能够和你们一起进步✊


http://www.kler.cn/a/392457.html

相关文章:

  • C++编程:利用环形缓冲区优化 TCP 发送流程,避免 Short Write 问题
  • AI制作ppt
  • Java的dto,和多表的调用
  • k8s集群安装(kubeadm)
  • 修改yolo格式的labels类别、删除yolo格式的labels类别
  • 【LeetCode】【算法】55. 跳跃游戏
  • wordpress实用功能A5资源网同款 隐藏下载框 支付框 需要登录才能查看隐藏的内容
  • 系统架构设计师论文:论软件维护方法及其应用
  • git同步fork和原始仓库
  • 【C#设计模式(5)——原型模式(Prototype Pattern)】
  • ubuntu24.04安装matlab失败
  • PDF 转 Word——10个实用优质工具大揭秘!
  • 大数据学习13之Scala基础语法(重点)
  • Redis做分布式锁
  • day12:版本控制器
  • 检测敏感词功能
  • CelebV-Text——从文本生成人脸视频的数据集
  • 2024 年 Postman 进行 Websocket 接口测试的图文教程
  • 激活函数解析:神经网络背后的“驱动力”
  • 练习LabVIEW第四十三题
  • 从0开始深度学习(26)——汇聚层/池化层
  • A. Turtle and Good Strings
  • 富格林:可信预判交易安全契机
  • P2356 弹珠游戏
  • HarmonyOS NEXT应用元服务开发Intents Kit(意图框架服务)上架配置指导
  • STM32 4X4 键盘