LeetCode算法题 (搜索二维矩阵)Day18!!!C/C++
https://leetcode.cn/problems/search-a-2d-matrix/description/
一、题目分析
给你一个满足下述两条属性的 m x n
整数矩阵:
- 每行中的整数从左到右按非严格递增顺序排列。
- 每行的第一个整数大于前一行的最后一个整数。
给你一个整数 target
,如果 target
在矩阵中,返回 true
;否则,返回 false
。
二、示例分析
输入:matrix = [[1,3,5,7],[10,11,16,20],[23,30,34,60]], target = 3 输出:true示例 2:
输入:matrix = [[1,3,5,7],[10,11,16,20],[23,30,34,60]], target = 13 输出:false
从题目及示例可知,我们的任务是在一个二维数组中查找目标值。若目标值存在于该二维数组中,返回true
;否则,返回false
。
今天的题目是一道经典的二分查找模板题。之前我们已经分享过二分算法相关内容,初次接触或有所遗忘的同学,可以点击链接回顾一下哦!https://blog.csdn.net/m0_75144071/article/details/145009380?spm=1001.2014.3001.5501
三、解题思路&代码实现
方法一:暴力法
在之前的题目分享中,我们多次强调了暴力法的重要性。这种方法的核心思想是:题目要求什么,我们就直接实现什么,暂时不考虑优化。对于初学者来说,先确保能够完成题目要求是最重要的!
所以暴力法我们也不难想出,题目要求在二维数组中搜索一个目标值,那么我们就直接枚举这个二维数组,如果枚举到目标值直接return true即可。下面看一下具体代码!
class Solution {
public:bool searchMatrix(vector<vector<int>>& matrix, int target) {// 遍历二维数组的每一行for (int i = 0; i < matrix.size(); i++) {// 遍历当前行的每一个元素for (int j = 0; j < matrix[i].size(); j++) {// 如果找到目标值,立即返回trueif (matrix[i][j] == target)return true;}}// 遍历完整个数组后仍未找到目标值,返回falsereturn false;}
};
方法二:二分算法(逐行二分)
方法一虽然简单,在LeetCode上也能顺利通过,但这是因为本题的数据量较小。即便n和m都取最大值100,数据范围也只有10^4。如果遇到数据范围较大的情况,方法一可能就难以通过所有测试用例了。
这时,更高效的算法就该登场了!二分查找算法的时间复杂度仅为O(logn),相比方法一的O(mn)有了显著提升,运行速度将大大提高。下面来看一下具体的实现代码!(下方代码的时间复杂度为O(Mlogn),这里请大家自行分析一下!)
class Solution {
public:bool searchMatrix(vector<vector<int>>& matrix, int target) {// 遍历二维数组的每一行for (int i = 0; i < matrix.size(); i++) {// 初始化二分查找的左右边界:左边界为0,右边界为当前行的最后一个元素索引int left = 0, right = matrix[i].size() - 1;// 二分查找循环:当左边界不超过右边界时继续搜索while (left <= right) {// 计算中间位置:使用位运算 >> 1 代替除以2,效率更高int mid = left + right >> 1;// 中间元素小于目标值,说明目标在右半部分,更新左边界if (matrix[i][mid] < target)left = mid + 1;// 中间元素大于目标值,说明目标在左半部分,更新右边界else if (matrix[i][mid] > target)right = mid - 1;// 找到目标值,立即返回trueelsereturn true; }}// 所有行搜索完毕后仍未找到目标值,返回falsereturn false;}
};
具体的思路就是,我们把二维数组想象成有m个大小为n的一维数组,每次去大小为n的二维数组中搜索目标值。而二分算法中最关键的一点,就是需要有序,题目中给出了每行内部有序,所以我们不用在对数组进行排序。
方法三:二分算法(库函数优化)
方法二的时间复杂度已是最优,不过我们可以进一步简化代码实现。
这里就要用到我们C++自带的库函数了,C++中内涵两个二分的库函数,分别是upper_bound和lower_bound。下面来带大家简单了解一下这两个函数的功能。
函数
返回值规则
等价元素处理
[10,20,20,30]
lower_bound(val)
返回
第一个≥val
的元素位置
指向第一个等于
val
的元素
lower_bound(20)
→ 指向第一个
20
(索引1)
upper_bound(val)
返回
第一个>val
的元素位置
指向最后一个等于
val
的
下一个位置
upper_bound(20)
→ 指向
30
(索引3)
// 在 [first, last) 范围内查找 iterator lower_bound(iterator first, iterator last, const T& val); iterator upper_bound(iterator first, iterator last, const T& val);
其中first和last两个参数为迭代器,表示搜索的范围(左闭右开区间)val表目标值。
如果找到则返回第一个满足的条件的元素的迭代器,若未找到,则返回last。
在这道题中,我们应该选择 lower_bound
而非 upper_bound
,因为 lower_bound
能够精准定位到第一个大于或等于目标值的元素,而这正是我们需要的。具体分析如下:
- 目标明确:题目要求判断二维数组中是否存在目标值
target
,我们需要找到第一个等于target
的位置。 lower_bound
的优势:它返回的迭代器指向第一个大于或等于target
的元素。如果该元素恰好等于target
,则说明存在;否则(元素大于target
或超出数组范围),说明不存在。upper_bound
的局限性:它返回的是第一个大于target
的元素,无法直接判断target
是否存在。即使存在,返回的位置也会跳过目标值,需要额外向前查找,增加复杂度。
下面来看一下具体的代码实现!
class Solution {
public:bool searchMatrix(vector<vector<int>>& matrix, int target) {// 遍历二维数组的每一行for (auto& row : matrix) {// 对当前行使用 lower_bound 进行二分查找// lower_bound 返回第一个 >=target 的元素迭代器auto it = lower_bound(row.begin(), row.end(), target);// 检查迭代器是否有效(未越界)且找到的元素等于 targetif (it != row.end() && *it == target)return true; // 找到目标值,返回 true}return false; // 所有行遍历完毕,未找到目标值}
};
使用 C++ 的 lower_bound
库函数确实能让代码的简洁性和可读性得到显著提升,同时还能减少手动实现二分查找时容易出现的边界条件错误。不过,我强烈建议大家在熟练掌握二分查找的底层逻辑,能够在任何二分题目中手写出正确的二分算法之后,再去使用这两个库函数。
方法四:二分算法(压缩映射)
以上的二分算法的时间复杂度都为O(M logn),其实还可以在对这段代码进行进一步的优化,也就是压缩映射。
压缩映射利用了空间的连续性二维数组在内存中通常按行优先存储(如 C++),即同一行的元素连续存储。通过公式 k = i×n + j
,可将二维位置无损压缩为一维索引,保持内存连续性。
而题目也给出了行内部有序与行与行之间有序。所以映射以后的数组也是保持有序的。
核心映射公式
对于一个 m 行 n 列的二维数组
matrix
,其元素matrix[i][j]
可映射为一维数组的索引k
:
k=i×n+j其中:
i
是行索引(范围:0 ≤ i < m
)j
是列索引(范围:0 ≤ j < n
)k
是一维索引(范围:0 ≤ k < m×n
)逆映射公式:从一维索引
k
恢复二维坐标:
i=⌊k/n⌋,j=k%n
关于公式推导,留给同学们作为练习。接下来我们直接进入算法优化部分。
class Solution {
public:bool searchMatrix(vector<vector<int>>& matrix, int target) {int m = matrix.size();int n = matrix[0].size();// 将二维矩阵视为一维有序数组进行二分查找// 初始化左右边界:左边界为0,右边界为矩阵元素总数减1int left = 0, right = m * n - 1;// 标准二分查找循环条件while (left <= right) {// 计算中间索引,避免(left+right)可能的整数溢出int mid = left + (right - left) / 2;// 将一维索引转换为二维矩阵中的行列坐标// mid / n 计算行号,mid % n 计算列号int val = matrix[mid / n][mid % n];// 找到目标值,立即返回if (val == target)return true;// 当前值小于目标值,调整左边界到mid+1else if (val < target)left = mid + 1;// 当前值大于目标值,调整右边界到mid-1elseright = mid - 1;}// 二分查找结束后仍未找到目标值return false;}
};
四、题目总结
一、核心考点
本题为经典的有序矩阵二分查找问题,主要考察以下能力:
- 有序性利用:通过矩阵的 “每行内部有序” 和 “行间递增” 特性,将二维搜索转化为一维问题。
- 二分查找算法:包括手动实现二分逻辑、使用标准库函数(如
lower_bound
)、以及通过数学映射(压缩映射)优化效率。
二、关键思路与解法对比
解法 | 时间复杂度 | 空间复杂度 | 核心逻辑 |
---|---|---|---|
暴力法 | O(mn) | O(1) | 逐行逐元素遍历,适用于小规模数据。 |
逐行二分 | O(mlogn) | O(1) | 对每行独立二分查找,利用每行有序性。 |
库函数优化 | O(mlogn) | O(1) | 使用 lower_bound 简化代码,避免手动处理边界。 |
压缩映射 | O(log(mn)) | O(1) | 将二维矩阵映射为一维有序数组,全局二分查找,效率最优。 |
三、核心知识点
-
二分查找模板:
- 循环条件:
left <= right
(闭区间)或left < right
(开区间)。 - 中点计算:
mid = left + (right - left) / 2
(避免整数溢出)。 - 边界调整:根据中点值与目标值的大小关系收缩搜索区间。
- 循环条件:
-
压缩映射原理:
- 二维坐标转一维索引:
k = i \times n + j
(n
为列数)。 - 一维索引转二维坐标:
i = k // n
,j = k % n
。 - 适用条件:矩阵需全局有序(每行首元素 > 前一行尾元素)。
- 二维坐标转一维索引:
-
C++ 标准库函数:
lower_bound
:返回第一个**≥目标值**的元素位置,用于判断存在性。upper_bound
:返回第一个 **> 目标值 ** 的元素位置,用于范围查询。
四、易错点与优化建议
-
边界条件:
- 空矩阵处理:需先判断
matrix.size() == 0
或matrix[0].size() == 0
。 - 索引越界:确保一维索引
k
在[0, m*n-1]
范围内。
- 空矩阵处理:需先判断
-
效率优化:
- 若矩阵全局有序,优先使用压缩映射的全局二分(O(log(mn)))。
- 避免重复造轮子:熟练掌握二分逻辑后,合理使用
lower_bound
提升代码简洁性。
五、总结
本题通过不同层次的解法展示了算法优化的思路:从暴力枚举到利用有序性的二分查找,再到通过数学映射实现全局最优解。核心在于深入理解题目条件(有序性),并选择合适的数据结构与算法降低时间复杂度。熟练掌握二分查找的原理和变种,是解决此类问题的关键。谢谢大家的收看!荆轲刺秦!!!
相关文章:

LeetCode算法题 (搜索二维矩阵)Day18!!!C/C++
https://leetcode.cn/problems/search-a-2d-matrix/description/ 一、题目分析 给你一个满足下述两条属性的 m x n 整数矩阵: 每行中的整数从左到右按非严格递增顺序排列。每行的第一个整数大于前一行的最后一个整数。 给你一个整数 target ,如果 ta…...

VectorStore 组件深入学习与检索方法
考虑到目前市面上的向量数据库众多,每个数据库的操作方式也无统一标准,但是仍然存在着一些公共特征,LangChain 基于这些通用的特征封装了 VectorStore 基类,在这个基类下,可以将方法划分成 6 种: 相似性搜…...

HackMyVM-First
信息搜集 主机发现 ┌──(kali㉿kali)-[~] └─$ nmap -sn 192.168.43.0/24 Starting Nmap 7.95 ( https://nmap.org ) at 2025-05-31 06:13 EDT Nmap scan report for 192.168.43.1 Host is up (0.0080s latency). MAC Address: C6:45:66:05:91:88 (Unknown) …...
30V/150A MOSFET 150N03在无人机驱动动力系统中的性能边界与热设计挑战
产品技术概述 150N03 是一款基于沟槽式工艺(Trench Technology)的N沟道功率MOSFET,其核心价值在于: 电压/电流规格:VDSS30V, ID150A (Tc25℃) 工艺特征:高密度元胞设计实现超低导通电阻 双面散热架构:顶部裸露铜架底…...
数据共享交换平台之数据资源目录
依据信息资源体系规范,构建多维度、多层级的资源目录体系,完整的展示和管理资源目录。资源目录提供以下功能: 多层级资源目录展示,能够将资源目录按照技术维度和管理维度进行分类管理,并能够将资源目录按照数据湖、基础…...

跨平台浏览器集成库JxBrowser 支持 Chrome 扩展程序,高效赋能 Java 桌面应用
JxBrowser 是 TeamDev 开发的跨平台库,用于在 Java 应用程序中集成 Chromium 浏览器。它支持 HTML5、CSS3、JavaScript 等,具备硬件加速渲染、双向 Java 与 JavaScript 连接、丰富的事件监听等功能,能处理网页保存、打印等操作,助…...

WEBSTORM前端 —— 第3章:移动 Web —— 第3节:移动适配
目录 一、移动Web基础 1.谷歌模拟器 2.屏幕分辨率 3.视口 4.二倍图 二、适配方案 三、rem 适配方案 四、less 1.less – 简介 2.less – 注释 3.less – 运算 4.less – 嵌套 5.less – 变量 6.less – 导入 7.less – 导出 8.less – 禁止导出 五…...
38.springboot使用rabbitmq
pom依赖 <!--amqp依赖,包含RabbitMQ--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId></dependency> 配置文件添加 spring:application:name: message…...

弱光环境下如何手持相机拍摄静物:摄影曝光之等效曝光认知
写在前面 博文内容为一次博物馆静物拍摄笔记的简单总结内容涉及:弱光环境拍摄静物如何选择,以及等效曝光的认知理解不足小伙伴帮忙指正 😃,生活加油 我看远山,远山悲悯 持续分享技术干货,感兴趣小伙伴可以关注下 _ 采…...
Selenium Manager中文文档
1. 什么是 Selenium Manager(测试版) Selenium Manager 是 Selenium 官方提供的命令行工具(用 Rust 实现),用于自动管理浏览器及其驱动(chromedriver、geckodriver、msedgedriver 等)。从 Sele…...
WEB安全--SQL注入--MSSQL注入
一、SQLsever知识点了解 1.1、系统变量 版本号:version 用户名:USER、SYSTEM_USER 库名:DB_NAME() SELECT name FROM master..sysdatabases 表名:SELECT name FROM sysobjects WHERE xtypeU 字段名:SELECT name …...

【HTML】基础学习【数据分析全栈攻略:爬虫+处理+可视化+报告】
- 第 102 篇 - Date: 2025 - 05 - 31 Author: 郑龙浩/仟墨 文章目录 HTML 基础学习一 了解HTML二 HTML的结构三 HTML标签1 标题2 文本段落3 换行4 加粗、斜体、下划线5 插入图片6 添加链接7 容器8 列表9 表格10 class类 HTML 基础学习 一 了解HTML 一个网页分为为三部分&…...
SAP Business ByDesign:无锡哲讯科技赋能中大型企业云端数字化转型
云端ERP时代,中大型企业的智能化引擎 在数字经济高速发展的今天,中大型企业面临着全球化竞争、供应链复杂化、数据安全等多重挑战。传统的本地化ERP系统已无法满足企业快速响应市场变化的需求,而SAP Business ByDesign(ByD&…...
华为OD机考2025B卷 - 无向图染色(Java Python JS C++ C )
最新华为OD机试 真题目录:点击查看目录 华为OD面试真题精选:点击立即查看 题目描述 给一个无向图染色,可以填红黑两种颜色,必须保证相邻两个节点不能同时为红色,输出有多少种不同的染色方案? 输入描述 第一行输入M(图中节点数) N(边数) 后续N行格式为:V1 V2表示…...
计算机网络学习20250528
地址解析协议ARP 实现IP地址和Mac地址的转换 ARP工作原理: 每台主机或路由器都有一个ARP表,表项:<IP地址,Mac地址,TTL>(TTL一般为20分钟) 主机产生ARP查询分组,包含源目的IP地…...

Next.js路由导航完全指南
在前端框架(如 React、Vue 等)或移动端开发中,路由系统是实现页面 / 界面导航的核心机制。Next.js 采用 文件系统路由(File System Routing),即根据项目目录结构自动生成路由。 Next.js 目前有两套路由解决…...

五、web安全--XSS漏洞(1)--XSS漏洞利用全过程
本文章仅供学习交流,如作他用所承受的法律责任一概与作者无关1、XSS漏洞利用全过程 1.1 寻找注入点:攻击者首先需要找到目标网站中可能存在XSS漏洞的注入点。这些注入点通常出现在用户输入能够直接输出到页面,且没有经过适当过滤或编码的地方…...

【C++高级主题】命令空间(六):重载与命名空间
目录 一、候选函数与命名空间:重载的 “搜索范围” 1.1 重载集的构成规则 1.2 命名空间对候选函数的隔离 二、重载与using声明:精准引入单个函数 2.1 using声明与重载的结合 2.2 using声明的冲突处理 三、重载与using指示:批量引入命名…...
利用 Python 爬虫获取淘宝商品详情
在电商领域,淘宝作为中国最大的在线零售平台,拥有海量的商品信息。对于开发者、市场分析师以及电商研究者来说,能够从淘宝获取商品详情信息,对于市场分析、价格比较、商品推荐等应用场景具有重要价值。本文将详细介绍如何使用 Pyt…...
动态拼接内容
服务器端模板引擎(Server-Side Template Engine) 的特性,比如 JSP(Java Server Pages)、ASP.NET、PHP 等技术中常用的 <% %> 语法。 它的核心作用是: 动态拼接内容:在 HTML 中嵌入编程语…...

Tomcat运行比较卡顿进行参数调优
在Tomcat conf/catalina.bat或catalina.sh中 的最上面增加参数 1. 初步调整参数(缓解问题) set JAVA_OPTS -Xms6g -Xmx6g -Xmn3g # 增大新生代,减少对象过早晋升到老年代 -XX:MetaspaceSize256m -XX:MaxMetaspaceS…...
java直接获取MyBatis将要执行的动态sql命令(不是拦截器方式)
目录 前言 一. 准备数据 1. 传输过来的json条件数据 2. mybatis 配置的动态sql 3. 想要的最终会执行的sql并返回给页面展示 二. 实现方式 三. 最终代码 前言 1.在平常开发过程中,MyBatis使用时非常多的,一般情况下我们只需要在控制台看看MyBatis输出的日志,要不就是实…...

C++四种类型转换方式
const_cast,去掉(指针或引用)常量属性的一个类型转换,但需要保持转换前后类型一致static_cast,提供编译器认为安全的类型转换(最常使用)reinterpret_cast,类似于c语言风格的强制类型转换,不保证安全;dynamic_cast,主要用于继承结构中…...

Canvas: trying to draw too large(256032000bytes) bitmap.
1、错误展示 测试了一下一张图片的显示,发现二个手机上测试的结果不一样,配制好一些的手机,直接就通过,但是屏小一些的测试手机上,直接报下面的错误。 这个意思是图片太大了,直接就崩了。 2、代码编写 lo…...
【深度学习-pytorch篇】5. 卷积神经网络与LLaMA分类模型
卷积神经网络与LLaMA分类模型 一、卷积操作基础 卷积是深度学习中用于提取局部特征的核心操作,特别适用于图像识别任务。 自定义二维卷积函数示例 以下函数实现了一个简化版的二维卷积: def convolve2D(image, kernel, padding0, strides1):kernel …...
matlab全息技术中的菲涅尔仿真成像
matlab全息技术中的菲涅尔仿真成像程序。 傅里叶法(重建距离得大)/Fresnel.m , 545 傅里叶法(重建距离得大)/FresnelB.m , 548 傅里叶法(重建距离得大)/Fresnel_solution.m , 1643 傅里叶法(重…...
基于对比学习的推荐系统开发方案,使用Python在PyCharm中实现
以下是一个基于对比学习的推荐系统开发方案,使用Python在PyCharm中实现。本文将详细阐述技术原理、系统设计和完整代码实现。 基于对比学习的推荐系统开发方案 一、技术背景与原理 1.1 对比学习核心思想 对比学习(Contrastive Learning)通过最大化正样本相似度、最小化负…...

网络协议之办公室网络是怎样的?
写在前面 本文来看下办公室网络怎样的。 1:正文 如果是在一个寝室中组件一个局域网还是比较简单的,只需要一个交换机,然后大家的电脑全部连接到这个交换机上就行了,之后所有的电脑设置CIDR保证在一个局域网就可以了。但是&#…...
鸿蒙OSUniApp PWA开发实践:打造跨平台渐进式应用#三方框架 #Uniapp
UniApp PWA开发实践:打造跨平台渐进式应用 前言 在过去的一年里,我们团队一直在探索如何利用UniApp框架开发高性能的PWA应用。特别是随着鸿蒙系统的普及,我们积累了不少有价值的实践经验。本文将分享我们在开发过程中的技术选型、架构设计和…...

uni-data-picker级联选择器、fastadmin后端api
记录一个部门及部门人员选择的功能,效果如下: 组件用到了uni-ui的级联选择uni-data-picker 开发文档:uni-app官网 组件要求的数据格式如下: 后端使用的是fastadmin,需要用到fastadmin自带的tree类生成部门树 &#x…...