【力扣刷题 | 第十六题】

这篇具有很好参考价值的文章主要介绍了【力扣刷题 | 第十六题】。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

【力扣刷题 | 第十六题】,【力扣刷题】,leetcode,数学建模,算法,c++,开发语言

目录

前言:

198. 打家劫舍 - 力扣(LeetCode)

213. 打家劫舍 II - 力扣(LeetCode)

 总结:


前言:

我们今天继续刷动态规划的题,希望大家可以和我一起坚持下去。

198. 打家劫舍 - 力扣(LeetCode)

你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。

给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。

【力扣刷题 | 第十六题】,【力扣刷题】,leetcode,数学建模,算法,c++,开发语言

 解题思路:我们要先快速确定出这道题的解题方向,我们读题后发现:当前房间偷不偷,取决于它前一个房间有没有被偷,因此可以确定出房间之间是存在这样一个递推关系的,因此我们确定了动态规划的思路,既然是动态规划,我们就严格按照动态规划五步走:

1.确定dp数组的含义以及下标的含义dp[i]表示包含这个房间他所能偷盗的最大金币的总和。

2.递推公式:我们用图片举例,假设此时我们要判断到最后一个房间的时候最大的金币数

其实就两个状态我们分类讨论:

1.偷最后一个房间:【力扣刷题 | 第十六题】,【力扣刷题】,leetcode,数学建模,算法,c++,开发语言

 既然5房间决定要偷了,那么4房间一定不偷,那么此时能够获得到的最大金币dp[5]其实就等于nums[5]+dp[3]。我们要理解正确理解dp数组的含义,才可以理解这个公式。

我们这里的下标只是为了方便理解,实际上我们在构建的时候,dp数组是从0开始的,也就是说dp[0]就是第一次房间能够偷到的最大金币数。

2.不偷最后一个房间:
【力扣刷题 | 第十六题】,【力扣刷题】,leetcode,数学建模,算法,c++,开发语言

 既然5房间不偷,那么此时能够得到的最大金币 dp[5 ]= dp[4],此时我们的问题就又回到了对dp[4]进行讨论,也就是对4号房间再次进行偷与不偷的讨论。

经过这个讲解,相信大家其实对打家劫舍问题的递推思路已经清晰:我们每一次比较这个这个房间偷与不偷所得到的金币数量,选择较大的作为dp数组的元素,这样不断递推,最后返回最后一个房间对应的dp数组的元素。

公式为: dp[i]=max(nums[i]+dp[i-2],dp[i-1]);

 3.dp数组的初始化:我们根据递推公式就可以知道只需要初始化dp[0]与dp[1]的值就好了。其实二者的初始化很好理解:
        dp[0]:从头开始包含第一个房间的最大金币数,那么当前只有一个房间,要想得到最大金币数就必须偷这个房间,那就是dp[0]=nums[0]。

        dp[1]:从头开始到第二间房间的最大金币数,因为我们不能偷相邻的两个房间,那么想要得到最大的金币数,就只能偷1或者偷2,选择最大的偷。那么就是dp[1]=max(dp[0],dp[1])。

4.遍历顺序:根据公式可得是从前往后推,遍历顺序自然也是从前往后。

经过我们详细的分析,代码的框架其实就已经搭建起来了,我们要做的只剩下补全这个框架。

class Solution {
public:
    int rob(vector<int>& nums) {
        if(nums.size()==1)
        {
            return nums[0];
        }
        else if(nums.size()==2)
        {
            return max(nums[0],nums[1]);
        }
       vector<int>dp(nums.size());
       dp[0]=nums[0];
       dp[1]=max(nums[0],nums[1]);
       for(int i=2;i<nums.size();i++)
       {
           dp[i]=max(nums[i]+dp[i-2],dp[i-1]);
       }       
       return dp[nums.size()-1];
    }
};

213. 打家劫舍 II - 力扣(LeetCode)

你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金。这个地方所有的房屋都 围成一圈 ,这意味着第一个房屋和最后一个房屋是紧挨着的。同时,相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警 。

给定一个代表每个房屋存放金额的非负整数数组,计算你 在不触动警报装置的情况下 ,今晚能够偷窃到的最高金额。

【力扣刷题 | 第十六题】,【力扣刷题】,leetcode,数学建模,算法,c++,开发语言

 其实这道题就是把改变了房间结构,让首尾相连,房间结构从线性变为了环形。

【力扣刷题 | 第十六题】,【力扣刷题】,leetcode,数学建模,算法,c++,开发语言其实就是分类讨论:

因为此时首尾元素相连,因此我们在选择的时候只有两种可能:

1.一定不偷尾。

2.一定不偷首。

【力扣刷题 | 第十六题】,【力扣刷题】,leetcode,数学建模,算法,c++,开发语言

 

在明确逻辑之后,代码就非常明确了:

class Solution {
public:
    int rob(vector<int>& nums) {

        if (nums.size() == 0) 
        {
            return 0;
        }
        if (nums.size() == 1)
        { 
            return nums[0];
        }
        int result1 = getmax(nums, 0, nums.size() - 2); //不对首进行考虑
        int result2 = getmax(nums, 1, nums.size() - 1); //不对尾进行考虑
        return max(result1, result2);
    }
    
    int getmax(vector<int>& nums, int start, int end) {
        if (end == start) return nums[start];
        vector<int> dp(nums.size());
        dp[start] = nums[start];
        dp[start + 1] = max(nums[start], nums[start + 1]);
        for (int i = start + 2; i <= end; i++) {
            dp[i] = max(dp[i - 2] + nums[i], dp[i - 1]);
        }
        return dp[end];
    }
};    

我们对改动做一下讲解:该函数的目的是计算在[start,end]范围内选择数字进行相加得到的最大和,其中每个数字只能选择一次。函数的实现过程如下:

1. 如果开始位置和结束位置相等,则直接返回数组下标为start的数字作为最大和。
2. 首先,我们定义一个大小与原始数组相同的dp数组,dp[i]表示在范围[0,i]内选择数字得到的最大和。
3. 然后,我们初始化dp[0]为nums[0],dp[1]为max(nums[0], nums[1]),因为在第一和第二个位置的数字中选择最大的那个能够确保我们得到最大和。
4. 接下来,我们从第三个位置(即start+2)开始,循环遍历整个数组。在每个位置i处,我们有两种选择:

  • 选择当前位置i的数字,这时最大和为dp[i-2]+nums[i];
  • 不选择当前位置i的数字,这时最大和为dp[i-1]。

5. 将两种选择的结果取max,更新dp[i]。
6. 最后,返回dp[end]作为[start,end]范围内选择数字相加得到的最大和。

需要注意的是,该算法的时间复杂度为O(N),其中N为数组的长度。

 总结:

        打家劫舍类型题目里面给我们提供的这个算法思路真的很精彩,不愧是动态规划的经典例题。

如果我的内容对你有帮助,请点赞,评论,收藏。创作不易,大家的支持就是我坚持下去的动力!

【力扣刷题 | 第十六题】,【力扣刷题】,leetcode,数学建模,算法,c++,开发语言

 


 文章来源地址https://www.toymoban.com/news/detail-606876.html

到了这里,关于【力扣刷题 | 第十六题】的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • leetcode 力扣刷题 旋转矩阵(循环过程边界控制)

    下面的题目的主要考察点都是,二维数组从左上角开始顺时针(或者逆时针)按圈遍历数组的过程。顺时针按圈遍历的过程如下: 对于每一圈,分为四条边 ,循环遍历就好。这时,对于 四个角 的元素的处理,可以将四条边的遍历分为以下两种情况: 第一种:每条边都从对

    2024年02月12日
    浏览(48)
  • 【leetcode 力扣刷题】移除链表元素 多种解法

    题目链接:203.移除链表元素 题目内容: 理解题意:就是单纯的删除链表中所有值等于给定的val的节点。上一篇博客中介绍了链表的基础操作,在删除链表中节点时,需要注意的是头节点: 如果没有虚拟头节点,那么对头节点的删除需要做不同的处理,head = head-next; 如果有

    2024年02月12日
    浏览(48)
  • 【leetcode 力扣刷题】链表基础知识 基础操作

    在数据结构的学习过程中,我们知道线性表【一种数据组织、在内存中存储的形式】是线性结构的,其中线性表包括顺序表和链表。数组就是顺序表,其各个元素在内存中是连续存储的。 链表则是由 数据域 和 指针域 组成的 结构体 构成的,数据域是一个节点的数据,指针域

    2024年02月12日
    浏览(39)
  • 【leetcode 力扣刷题】回文串相关题目(KMP、动态规划)

    题目链接:5. 最长回文子串 题目内容: 题目就是要我们找s中的回文子串,还要是最长的。其实想想,暴力求解也行……就是遍历所有的子串,同时判断是不是回文串,是的话再和记录的最大长度maxlen比较,如果更长就更新。时间复杂度直接变成O(n^3)。 优化的点在于,假设子

    2024年02月09日
    浏览(48)
  • 【leetcode 力扣刷题】字符串翻转合集(全部反转///部分反转)

    题目链接:344. 反转字符串 题目内容: 题目中重点强调了必须 原地修改 输入数组,即不能新建一个数组来完成字符串的反转。我们注意到: 原来下标为0的,反转后是size - 1【原来下标是size - 1的,反转后是0】; 原来下标是1的,反转后是size - 2【原来下标是size -2的,反转后

    2024年02月11日
    浏览(46)
  • 【leetcode 力扣刷题】字符串匹配之经典的KMP!!!

    以下是能用KMP求解的算法题,KMP是用于字符串匹配的经典算法【至今没学懂………啊啊啊】 题目链接:28. 找出字符串中第一个匹配项的下标 题目内容: 题意还是很好理解的,要在字符串haystack中查找一个完整的needle,即字符串匹配。 暴力求解就是用 两层循环 :haystack从第

    2024年02月09日
    浏览(42)
  • 【leetcode 力扣刷题】数学题之除法:哈希表解决商的循环节➕快速乘求解商

    题目链接:166. 分数到小数 题目内容: 题目是要我们把一个分数变成一个小数,并以字符串的形式返回。按道理,直接将分子numerator除以分母denominator就得到了小数,转换成string返回就好。题目要求里指出了特殊情况—— 小数部分如果有循环,就把循环节括在括号里 。 那么

    2024年02月10日
    浏览(40)
  • 力扣经典150题第三十六题:旋转图像

    本篇博客介绍了力扣经典150题中的第三十六题:旋转图像。题目要求将给定的 n × n 二维矩阵顺时针旋转90度,并要求在原地进行修改。 给定一个 n × n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。 示例 1: 输入:matrix = [[1,2,3],[4,5,6],[7,8,9]] 输出:[[7,4,1],[8

    2024年04月28日
    浏览(41)
  • 数据结构:力扣刷题

      给你一个  升序排列  的数组  nums  ,请你  原地  删除重复出现的元素,使每个元素  只出现一次  ,返回删除后数组的新长度。元素的  相对顺序  应该保持  一致  。然后返回  nums  中唯一元素的个数。 考虑  nums  的唯一元素的数量为  k  ,你需要做以下事情确

    2024年02月13日
    浏览(44)
  • 【力扣刷题 | 第七天】

    今天我们将会进入栈与队列的刷题篇章,二者都是经典的数据结构,熟练的掌握栈与队列实现可以巧妙的解决有些问题。 请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(push、pop、peek、empty): 实现 MyQueue 类: void push(int x) 将元素 x 推到队列的

    2024年02月09日
    浏览(49)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包