力扣练习题(2024/4/15)

news2024/11/27 20:24:24

1打家劫舍

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

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

示例 1:

输入:[1,2,3,1]
输出:4
解释:偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。
     偷窃到的最高金额 = 1 + 3 = 4 。

示例 2:

输入:[2,7,9,3,1]
输出:12
解释:偷窃 1 号房屋 (金额 = 2), 偷窃 3 号房屋 (金额 = 9),接着偷窃 5 号房屋 (金额 = 1)。
     偷窃到的最高金额 = 2 + 9 + 1 = 12 。

提示:

  • 1 <= nums.length <= 100
  • 0 <= nums[i] <= 400

思路:

大家如果刚接触这样的题目,会有点困惑,当前的状态我是偷还是不偷呢?

仔细一想,当前房屋偷与不偷取决于 前一个房屋和前两个房屋是否被偷了。由于不能偷相邻的房屋,所以偷窃当前房屋的决策实际上是一个在两种选择中取最优值的问题:偷窃当前房屋或者不偷窃当前房屋。因此,我们使用动态规划来记录偷窃到每个房屋时的最大金额,通过比较偷窃当前房屋和不偷窃当前房屋两种选择的结果,来更新动态规划数组。

我们可以用一个数组 dp 来记录到每个房屋为止能够偷窃到的最高金额,其中 dp[i] 表示偷窃到第 i 个房屋时的最大金额。

具体的解题思路如下:

  1. 对于第一个房屋,最大金额就是该房屋内的现金数目。
  2. 对于第二个房屋,由于不能偷相邻的房屋,所以最大金额就是第一个房屋的金额和第二个房屋的金额中的较大值。
  3. 对于第三个房屋及之后的每个房屋,最大金额就是当前房屋金额加上前两个房屋中能够偷窃到的最大金额。
  4. 确定dp数组(dp table)以及下标的含义
  5. dp[i]:考虑下标i(包括i)以内的房屋,最多可以偷窃的金额为dp[i]

  6. 确定递推公式
  7. 决定dp[i]的因素就是第i房间偷还是不偷。

    如果偷第i房间,那么dp[i] = dp[i - 2] + nums[i] ,即:第i-1房一定是不考虑的,找出 下标i-2(包括i-2)以内的房屋,最多可以偷窃的金额为dp[i-2] 加上第i房间偷到的钱。

    如果不偷第i房间,那么dp[i] = dp[i - 1],即考 虑i-1房,然后dp[i]取最大值,即dp[i] = max(dp[i - 2] + nums[i], dp[i - 1]);

  8. dp数组如何初始化
  9. 从递推公式dp[i] = max(dp[i - 2] + nums[i], dp[i - 1]);可以看出,递推公式的基础就是dp[0] 和 dp[1]

    从dp[i]的定义上来讲,dp[0] 一定是 nums[0],dp[1]就是nums[0]和nums[1]的最大值即:dp[1] = max(nums[0], nums[1]);

  10. 确定遍历顺序
  11. dp[i] 是根据dp[i - 2] 和 dp[i - 1] 推导出来的,那么一定是从前到后遍历!

  12. 代码:

     

     

    class Solution {
    public:
        int rob(vector<int>& nums) {
            // 处理特殊情况:空数组和只有一个房屋的情况
            if (nums.size() == 0) return 0; // 如果房屋数量为0,则返回0
            if (nums.size() == 1) return nums[0]; // 如果只有一个房屋,则返回该房屋的金额
    
            // 初始化动态规划数组
            vector<int> dp(nums.size()); // 创建一个大小为nums.size()的数组dp,用于记录偷窃到每个房屋时的最大金额
            dp[0] = nums[0]; // 第一个房屋的最大金额就是该房屋内的现金数目
            dp[1] = max(nums[0], nums[1]); // 第二个房屋的最大金额为第一个房屋的金额和第二个房屋的金额中的较大值
    
            // 动态规划递推过程
            for (int i = 2; i < nums.size(); i++) {
                // 对于第三个房屋及之后的每个房屋,最大金额就是当前房屋金额加上前两个房屋中能够偷窃到的最大金额
                dp[i] = max(dp[i - 2] + nums[i], dp[i - 1]);
            }
    
            // 返回最终结果,即偷窃到的最高金额
            return dp[nums.size() - 1];
        }
    };

    2打家劫舍 II

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

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

    示例 1:

    输入:nums = [2,3,2]
    输出:3
    解释:你不能先偷窃 1 号房屋(金额 = 2),然后偷窃 3 号房屋(金额 = 2), 因为他们是相邻的。
    

    示例 2:

    输入:nums = [1,2,3,1]
    输出:4
    解释:你可以先偷窃 1 号房屋(金额 = 1),然后偷窃 3 号房屋(金额 = 3)。
         偷窃到的最高金额 = 1 + 3 = 4 。

    示例 3:

    输入:nums = [1,2,3]
    输出:3
    

    提示:

  13. 1 <= nums.length <= 100
  14. 0 <= nums[i] <= 1000

思路:

这个问题是「打家劫舍」问题的一个变种,房屋围成一圈,即第一个房屋和最后一个房屋相邻。因此,在考虑偷取的时候需要考虑首尾房屋不能同时偷取的情况。

解题思路可以借鉴动态规划的思想,但是需要分情况讨论:

  1. 如果偷取了第一间房屋,则最后一间房屋不能偷取,因此偷取范围为第一间到倒数第二间房屋;
  2. 如果没有偷取第一间房屋,则最后一间房屋可以选择偷取或不偷取,偷取范围为第二间到最后一间房屋。

因此,可以将问题分解为两个子问题,分别计算偷取第一间房屋和不偷取第一间房屋的最大金额,然后取两者中的最大值即可。

代码:


class Solution {
public:
    // 主函数,计算在不触动警报装置的情况下,能够偷窃到的最高金额
    int rob(vector<int>& nums) {
        if (nums.size() == 0) return 0; // 如果房屋数量为0,则返回0
        if (nums.size() == 1) return nums[0]; // 如果房屋数量为1,则返回唯一的房屋金额
        // 计算情况二:偷取第一间房屋
        int result1 = robRange(nums, 0, nums.size() - 2);
        // 计算情况三:不偷取第一间房屋
        int result2 = robRange(nums, 1, nums.size() - 1);
        // 返回两种情况中的最大值
        return max(result1, result2);
    }

    // 实现打家劫舍的逻辑,计算指定范围内的最大金额
    int robRange(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];
    }
};

3打家劫舍 III

小偷又发现了一个新的可行窃的地区。这个地区只有一个入口,我们称之为 root 。

除了 root 之外,每栋房子有且只有一个“父“房子与之相连。一番侦察之后,聪明的小偷意识到“这个地方的所有房屋的排列类似于一棵二叉树”。 如果 两个直接相连的房子在同一天晚上被打劫 ,房屋将自动报警。

给定二叉树的 root 。返回 在不触动警报的情况下 ,小偷能够盗取的最高金额 。

示例 1:

输入: root = [3,2,3,null,3,null,1]
输出: 7 
解释: 小偷一晚能够盗取的最高金额 3 + 3 + 1 = 7

示例 2:

输入: root = [3,4,5,1,3,null,1]
输出: 9
解释: 小偷一晚能够盗取的最高金额 4 + 5 = 9

提示:

  • 树的节点数在 [1, 104] 范围内
  • 0 <= Node.val <= 104

思路:

  1. 设计一个包含两个元素的数组 dpdp[0] 表示不偷当前节点能获得的最大金额,dp[1] 表示偷当前节点能获得的最大金额。
  2. 对于每个节点,有两种情况:偷或者不偷。
  3. 如果偷当前节点,则其左右子节点不能被偷,所以偷当前节点的最大金额为当前节点的值加上不偷左右子节点的最大金额。
  4. 如果不偷当前节点,则其左右子节点可以被偷或者不偷,所以不偷当前节点的最大金额为左右子节点偷或不偷的最大金额之和。
  5. 最后返回根节点偷或不偷的最大金额中的较大值。

代码:

class Solution {
public:
    // 主函数,计算在不触动警报装置的情况下,能够偷窃到的最高金额
    int rob(TreeNode* root) {
        // 调用辅助函数,获取根节点为起点的偷窃情况
        vector<int> result = robTree(root);
        // 返回偷窃根节点和不偷窃根节点的最大金额
        return max(result[0], result[1]);
    }
    
    // 辅助函数,计算以当前节点为根节点的偷窃情况
    // 返回长度为2的数组,0:不偷,1:偷
    vector<int> robTree(TreeNode* cur) {
        // 如果当前节点为空,返回{0, 0},表示不偷任何东西
        if (cur == NULL) return vector<int>{0, 0};
        // 递归调用,获取左右子树的偷窃情况
        vector<int> left = robTree(cur->left);
        vector<int> right = robTree(cur->right);
        // 偷当前节点,那么就不能偷左右子节点
        int val1 = cur->val + left[0] + right[0];
        // 不偷当前节点,那么可以偷也可以不偷左右子节点,取较大的情况
        int val2 = max(left[0], left[1]) + max(right[0], right[1]);
        // 返回当前节点偷与不偷的最大金额
        return {val2, val1};
    }
};

4最后一个单词的长度

给你一个字符串 s,由若干单词组成,单词前后用一些空格字符隔开。返回字符串中 最后一个 单词的长度。

单词 是指仅由字母组成、不包含任何空格字符的最大

子字符串

示例 1:

输入:s = "Hello World"
输出:5
解释:最后一个单词是“World”,长度为5。

示例 2:

输入:s = "   fly me   to   the moon  "
输出:4
解释:最后一个单词是“moon”,长度为4。

示例 3:

输入:s = "luffy is still joyboy"
输出:6
解释:最后一个单词是长度为6的“joyboy”。

提示:

  • 1 <= s.length <= 104
  • s 仅有英文字母和空格 ' ' 组成
  • s 中至少存在一个单词

思路:

由于字符串中至少存在一个单词,因此字符串中一定有字母。首先找到字符串中的最后一个字母,该字母即为最后一个单词的最后一个字母。

从最后一个字母开始继续反向遍历字符串,直到遇到空格或者到达字符串的起始位置。遍历到的每个字母都是最后一个单词中的字母,因此遍历到的字母数量即为最后一个单词的长度。

代码:

class Solution {
public:
    // 计算最后一个单词的长度
    int lengthOfLastWord(string s) {
        int i = s.size() - 1; // 从字符串末尾开始向前遍历
        int count = 0; // 计数器,用于记录最后一个单词的长度

        // 跳过末尾的空格
        while (s[i] == ' ') {
            i--;
        }

        // 计算最后一个单词的长度
        while (i >= 0 && s[i] != ' ') {
            i--;
            count++;
        }

        return count; // 返回最后一个单词的长度
    }
};

5市场分析 I

表: Users

+----------------+---------+
| Column Name    | Type    |
+----------------+---------+
| user_id        | int     |
| join_date      | date    |
| favorite_brand | varchar |
+----------------+---------+
user_id 是此表主键(具有唯一值的列)。
表中描述了购物网站的用户信息,用户可以在此网站上进行商品买卖。

表: Orders

+---------------+---------+
| Column Name   | Type    |
+---------------+---------+
| order_id      | int     |
| order_date    | date    |
| item_id       | int     |
| buyer_id      | int     |
| seller_id     | int     |
+---------------+---------+
order_id 是此表主键(具有唯一值的列)。
item_id 是 Items 表的外键(reference 列)。
(buyer_id,seller_id)是 User 表的外键。

表:Items

+---------------+---------+
| Column Name   | Type    |
+---------------+---------+
| item_id       | int     |
| item_brand    | varchar |
+---------------+---------+
item_id 是此表的主键(具有唯一值的列)。

编写解决方案找出每个用户的注册日期和在 2019 年作为买家的订单总数。

以 任意顺序 返回结果表。

查询结果格式如下。

示例 1:

输入:
Users 表:
+---------+------------+----------------+
| user_id | join_date  | favorite_brand |
+---------+------------+----------------+
| 1       | 2018-01-01 | Lenovo         |
| 2       | 2018-02-09 | Samsung        |
| 3       | 2018-01-19 | LG             |
| 4       | 2018-05-21 | HP             |
+---------+------------+----------------+
Orders 表:
+----------+------------+---------+----------+-----------+
| order_id | order_date | item_id | buyer_id | seller_id |
+----------+------------+---------+----------+-----------+
| 1        | 2019-08-01 | 4       | 1        | 2         |
| 2        | 2018-08-02 | 2       | 1        | 3         |
| 3        | 2019-08-03 | 3       | 2        | 3         |
| 4        | 2018-08-04 | 1       | 4        | 2         |
| 5        | 2018-08-04 | 1       | 3        | 4         |
| 6        | 2019-08-05 | 2       | 2        | 4         |
+----------+------------+---------+----------+-----------+
Items 表:
+---------+------------+
| item_id | item_brand |
+---------+------------+
| 1       | Samsung    |
| 2       | Lenovo     |
| 3       | LG         |
| 4       | HP         |
+---------+------------+
输出:
+-----------+------------+----------------+
| buyer_id  | join_date  | orders_in_2019 |
+-----------+------------+----------------+
| 1         | 2018-01-01 | 1              |
| 2         | 2018-02-09 | 2              |
| 3         | 2018-01-19 | 0              |
| 4         | 2018-05-21 | 0              |
+-----------+------------+----------------+

思路:-- 在用户表和订单表之间进行左连接,以保证即使某些用户在2019年没有订单也能够显示出来
-- 使用 left  join 来保留 users 表中的所有用户,即使他们在订单表中没有对应的记录
-- 使用 count() 函数来计算每个用户在2019年的订单数量
-- 使用 year() 函数来提取订单日期的年份,并将其与2019进行比较
-- 最后按照用户 ID 分组,并选择用户 ID、加入日期和2019年的订单数量作为结果

代码:

​

select 
    user_id as buyer_id, -- 选择用户 ID 作为买家 ID
    join_date, -- 选择用户的加入日期
    count(order_id) as orders_in_2019 -- 计算用户在2019年的订单数量
from 
    Users as u -- 从用户表中选择用户信息
left join 
    Orders as o on u.user_id = o.buyer_id and year(order_date)='2019' -- 使用左连接关联订单表,并筛选出2019年的订单
group by 
    user_id; -- 按照用户 ID 进行分组

​

​

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1599567.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数字孪生技术在医疗培训方面的应用

数字孪生技术在医疗培训方面的应用主要体现在以下几个方面&#xff0c;通过这些应用&#xff0c;数字孪生技术在医疗培训领域展现出巨大的潜力&#xff0c;有望改变传统的医学教育模式&#xff0c;提高医疗培训的效率和质量。北京木奇移动技术有限公司&#xff0c;专业的软件外…

记录 OpenHarmony 使用 request.uploadFile 时踩的坑

​ 开发环境 设备环境&#xff1a;OpenHarmony 4.1.x SDK 版本&#xff1a;API 10 开发模型&#xff1a;Stage 模型 IDLE: Dev Eco 4.1 官方文档 踩坑一&#xff1a;后台服务地址 上传文件依赖后台服务器&#xff0c;如果使用本地搭建的服务&#xff0c;是无法访问的&…

✌粤嵌—2024/4/10—简化路径

代码实现&#xff1a; 栈 // 分割/得到名字 char **split(const char *s, int *returnSize) {int n strlen(s);char **ans (char**)malloc(sizeof(char*) * n);int l 0, r;*returnSize 0;while (l < n) {while (l < n && s[l] /) { // 左&#xff1a;ll;}r …

鑫鹿助贷CRM系统:助力助贷行业实现智能商业转型

数字化时代&#xff0c;商业竞争愈发激烈&#xff0c;助贷行业如何把握商机、实现高效管理、打造高回报率的商业模式&#xff0c;成为了助贷行业老板们比较关注的问题&#xff0c;而鑫鹿助贷CRM管理系统&#xff0c;正是这场商业变革中的得力助手&#xff0c;系统功能完善&…

多普勒频移

下面从频谱的角度理解多普勒频移。 设目标以速度接近雷达&#xff0c;在时刻距离&#xff0c;则在任意时刻目标与雷达的距离为 设雷达发射信号为。设时刻发射的信号经过遇到目标&#xff0c;则由于目标与信号相向运动&#xff0c;有 得到&#xff0c;从而时刻发射的信号经过返回…

Nacos多服务共享配置 和集群搭建

多种配置优先级: Nacos本地集群搭建&#xff1a; 1.根据黑马的课&#xff1a;我们下载nacos&#xff0c;有安装包 解压到没中文的目录 2.进入conf目录&#xff0c;修改配置名字为cluster.conf 3.然后进入cluster.conf&#xff0c;添加内容。 127.0.0.1:8845 127.0.0.1.8846 1…

打一把王者的时间,学会web页面测试方法与测试用例编写

一、输入框 1、字符型输入框&#xff1a; &#xff08;1&#xff09;字符型输入框&#xff1a;英文全角、英文半角、数字、空或者空格、特殊字符“~&#xff01;#&#xffe5;%……&*&#xff1f;[]{}”特别要注意单引号和&符号。禁止直接输入特殊字符时&#xff0c;…

四.吊打面试官系列-数据库优化-Mysql锁和事务原理

前言 本篇文章主要讲解两块内容&#xff1a;Mysql中的锁和ACID原理&#xff0c;这2个部分是面试的时候被问的蛮多的看完本篇文章之后相信你对Mysql事务会有更深层次的理解&#xff0c;如果文章对你有所帮助请记得好评 一.Mysql中的锁 1.锁的分类 在Mysql中锁也分为很多种&a…

Linux高级IO——多路转接之epoll

本章代码Gitee地址&#xff1a;EpollServer 文章目录 1. epoll接口1.1 epoll_create1.2 epoll_wait1.3 epoll_ctl 2. epoll原理3. epoll_server4. epoll两种工作模式 1. epoll接口 1.1 epoll_create #include <sys/epoll.h> int epoll_create(int size);参数int size理…

强化学习(三)基于动态规划 Dynamic Programming 的求解方法

文章目录 1. 动态规划与强化学习的联系2. 利用动态规划求解最优价值函数2.1 案例背景2.2 策略评估&#xff08;预测&#xff09;2.3 策略迭代&#xff08;控制&#xff09; 在前文《强化学习的数学框架&#xff1a;马尔科夫决策过程 MDP》中&#xff0c;我们用马尔可夫过程抽象…

HTML注释标签与标题标签

目录 注释标签 标题标签 注释标签 如果需要在 HTML 文档中添加一些便于阅读和理解但又不需要显示在页面中的注释文字&#xff0c;就需要使用注释标签。注释不会显示在网页界面上&#xff0c;目的是提高代码的可读性 在HTML中&#xff0c;使用<!-- 和 -->包裹注释的内…

Spring底层如何执行?

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 Spring底层如何执行refresh()prepareRefresh() 准备刷新的工作initPropertySources() obtainFreshBeanFactory()refreshBeanFactory()AbstractRefreshableApplicati…

博客系统项目测试(selenium+Junit5)

在做完博客系统项目之后&#xff0c;需要对项目的功能、接口进行测试&#xff0c;利用测试的工具&#xff1a;selenium以及Java的单元测试工具Junit进行测试&#xff0c;下面式测试的思维导图&#xff0c;列出该项目需要测试的所有测试用例&#xff1a; 测试结果&#xff08;全…

链表拓展之双向链表

前言 在前面已经总结了单链表&#xff0c;有了单链表的基础会很好理解双链表的实现&#xff0c;忘记了可以跳转——>http://t.csdnimg.cn/GFPk9 接下来就由我带着各位看官来认识今天的主角吧~ 什么是双向链表 在单链表的基础上&#xff0c;它有两个方向的链接&#xff0c;一…

SpringBlade dict-biz/list SQL 注入漏洞复现

0x01 免责声明 请勿利用文章内的相关技术从事非法测试&#xff0c;由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失&#xff0c;均由使用者本人负责&#xff0c;作者不为此承担任何责任。工具来自网络&#xff0c;安全性自测&#xff0c;如有侵权请联系删…

一文看懂动态IP代理API

“动态”意味着每次连接或每隔一段时间&#xff0c;用户的IP地址都会发生改变。由于IP地址的不断变化&#xff0c;用户可以避免因频繁访问同一网站而导致的IP被封锁的问题。API叫做应用程序接口&#xff0c;是一种让软件之间相互通信的接口。API允许用户通过编程方式来调用动态…

【从浅学到熟知Linux】进程控制下篇=>进程程序替换与简易Shell实现(含替换原理、execve、execvp等接口详解)

&#x1f3e0;关于专栏&#xff1a;Linux的浅学到熟知专栏用于记录Linux系统编程、网络编程等内容。 &#x1f3af;每天努力一点点&#xff0c;技术变化看得见 文章目录 进程程序替换什么是程序替换及其原理替换函数execlexeclpexecleexecvexecvpexecvpeexecve 替换函数总结实现…

转行或者跳槽入职一家新公司,应该如何快速上手工作?

不管是干测试也好或者其它任何职业&#xff0c;没有谁会在一家公司待一辈子&#xff0c;转行不一定&#xff0c;但是跳槽是每一个打工人早晚都会面临的事情&#xff0c;今天就来跟大家聊聊这件事~ 入职一家新公司&#xff0c;你应该做什么可以最快速的上手工作&#xff1f; 这…

Python编程之旅:深入探索强大的容器——列表

在Python编程的世界中&#xff0c;容器&#xff08;Containers&#xff09;是一种用于存储多个项目的数据结构。其中&#xff0c;列表&#xff08;List&#xff09;是最常用且功能强大的容器之一。无论是初学者还是资深开发者&#xff0c;掌握列表的使用方法和技巧都是提升Pyth…

判断位数、按位输出、倒序输出(C语言)

一、运行结果&#xff1b; 二、源代码&#xff1b; # define _CRT_SECURE_NO_WARNINGS # include <stdio.h>int main() {//初始化变量值&#xff1b;int number 0;int i 1;int m 0;int z 0;int z1 0, z2 0, z3 0, z4 0;//提示用户&#xff1b;printf("请输…