LeetCode算法题 (搜索二维矩阵)Day18!!!C/C++

news2025/6/4 1:40:23

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++) {
                // 如果找到目标值,立即返回true
                if (matrix[i][j] == target)
                    return true;
            }
        }
        // 遍历完整个数组后仍未找到目标值,返回false
        return 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;
                // 找到目标值,立即返回true
                else
                    return true;        
            }
        }
        // 所有行搜索完毕后仍未找到目标值,返回false
        return 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 能够精准定位到第一个大于或等于目标值的元素,而这正是我们需要的。具体分析如下:

  1. 目标明确:题目要求判断二维数组中是否存在目标值 target,我们需要找到第一个等于 target 的位置
  2. lower_bound 的优势:它返回的迭代器指向第一个大于或等于 target 的元素。如果该元素恰好等于 target,则说明存在;否则(元素大于 target 或超出数组范围),说明不存在。
  3. 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);
            
            // 检查迭代器是否有效(未越界)且找到的元素等于 target
            if (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,右边界为矩阵元素总数减1
        int 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+1
            else if (val < target)
                left = mid + 1;
            // 当前值大于目标值,调整右边界到mid-1
            else
                right = mid - 1;
        }
        
        // 二分查找结束后仍未找到目标值
        return false;
    }
};

​

四、题目总结

一、核心考点

本题为经典的有序矩阵二分查找问题,主要考察以下能力:

  1. 有序性利用:通过矩阵的 “每行内部有序” 和 “行间递增” 特性,将二维搜索转化为一维问题。
  2. 二分查找算法:包括手动实现二分逻辑、使用标准库函数(如 lower_bound)、以及通过数学映射(压缩映射)优化效率。

二、关键思路与解法对比

解法时间复杂度空间复杂度核心逻辑
暴力法O(mn)O(1)逐行逐元素遍历,适用于小规模数据。
逐行二分O(mlogn)O(1)对每行独立二分查找,利用每行有序性。
库函数优化O(mlogn)O(1)使用 lower_bound 简化代码,避免手动处理边界。
压缩映射O(log(mn))O(1)将二维矩阵映射为一维有序数组,全局二分查找,效率最优。

三、核心知识点

  1. 二分查找模板

    • 循环条件:left <= right(闭区间)或 left < right(开区间)。
    • 中点计算:mid = left + (right - left) / 2(避免整数溢出)。
    • 边界调整:根据中点值与目标值的大小关系收缩搜索区间。
  2. 压缩映射原理

    • 二维坐标转一维索引:k = i \times n + jn 为列数)。
    • 一维索引转二维坐标:i = k // nj = k % n
    • 适用条件:矩阵需全局有序(每行首元素 > 前一行尾元素)。
  3. C++ 标准库函数

    • lower_bound:返回第一个**≥目标值**的元素位置,用于判断存在性。
    • upper_bound:返回第一个 **> 目标值 ** 的元素位置,用于范围查询。

四、易错点与优化建议

  1. 边界条件

    • 空矩阵处理:需先判断 matrix.size() == 0 或 matrix[0].size() == 0
    • 索引越界:确保一维索引 k 在 [0, m*n-1] 范围内。
  2. 效率优化

    • 若矩阵全局有序,优先使用压缩映射的全局二分(O(log(mn)))。
    • 避免重复造轮子:熟练掌握二分逻辑后,合理使用 lower_bound 提升代码简洁性。

五、总结

        本题通过不同层次的解法展示了算法优化的思路:从暴力枚举到利用有序性的二分查找,再到通过数学映射实现全局最优解。核心在于深入理解题目条件(有序性),并选择合适的数据结构与算法降低时间复杂度。熟练掌握二分查找的原理和变种,是解决此类问题的关键。谢谢大家的收看!荆轲刺秦!!!

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

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

相关文章

VectorStore 组件深入学习与检索方法

考虑到目前市面上的向量数据库众多&#xff0c;每个数据库的操作方式也无统一标准&#xff0c;但是仍然存在着一些公共特征&#xff0c;LangChain 基于这些通用的特征封装了 VectorStore 基类&#xff0c;在这个基类下&#xff0c;可以将方法划分成 6 种&#xff1a; 相似性搜…

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) …

跨平台浏览器集成库JxBrowser 支持 Chrome 扩展程序,高效赋能 Java 桌面应用

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

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 – 禁止导出 五…

弱光环境下如何手持相机拍摄静物:摄影曝光之等效曝光认知

写在前面 博文内容为一次博物馆静物拍摄笔记的简单总结内容涉及&#xff1a;弱光环境拍摄静物如何选择&#xff0c;以及等效曝光的认知理解不足小伙伴帮忙指正 &#x1f603;,生活加油 我看远山&#xff0c;远山悲悯 持续分享技术干货&#xff0c;感兴趣小伙伴可以关注下 _ 采…

【HTML】基础学习【数据分析全栈攻略:爬虫+处理+可视化+报告】

- 第 102 篇 - Date: 2025 - 05 - 31 Author: 郑龙浩/仟墨 文章目录 HTML 基础学习一 了解HTML二 HTML的结构三 HTML标签1 标题2 文本段落3 换行4 加粗、斜体、下划线5 插入图片6 添加链接7 容器8 列表9 表格10 class类 HTML 基础学习 一 了解HTML 一个网页分为为三部分&…

Next.js路由导航完全指南

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

五、web安全--XSS漏洞(1)--XSS漏洞利用全过程

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

【C++高级主题】命令空间(六):重载与命名空间

目录 一、候选函数与命名空间&#xff1a;重载的 “搜索范围” 1.1 重载集的构成规则 1.2 命名空间对候选函数的隔离 二、重载与using声明&#xff1a;精准引入单个函数 2.1 using声明与重载的结合 2.2 using声明的冲突处理 三、重载与using指示&#xff1a;批量引入命名…

Tomcat运行比较卡顿进行参数调优

在Tomcat conf/catalina.bat或catalina.sh中 的最上面增加参数 1. 初步调整参数&#xff08;缓解问题&#xff09; set JAVA_OPTS -Xms6g -Xmx6g -Xmn3g # 增大新生代&#xff0c;减少对象过早晋升到老年代 -XX:MetaspaceSize256m -XX:MaxMetaspaceS…

C++四种类型转换方式

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

Canvas: trying to draw too large(256032000bytes) bitmap.

1、错误展示 测试了一下一张图片的显示&#xff0c;发现二个手机上测试的结果不一样&#xff0c;配制好一些的手机&#xff0c;直接就通过&#xff0c;但是屏小一些的测试手机上&#xff0c;直接报下面的错误。 这个意思是图片太大了&#xff0c;直接就崩了。 2、代码编写 lo…

网络协议之办公室网络是怎样的?

写在前面 本文来看下办公室网络怎样的。 1&#xff1a;正文 如果是在一个寝室中组件一个局域网还是比较简单的&#xff0c;只需要一个交换机&#xff0c;然后大家的电脑全部连接到这个交换机上就行了&#xff0c;之后所有的电脑设置CIDR保证在一个局域网就可以了。但是&#…

uni-data-picker级联选择器、fastadmin后端api

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

8天Python从入门到精通【itheima】-62~63

目录 第六章开始-62节-数据容器入门 1.学习目标 2.为什么要学习数据容器&#xff1f; 3.什么是Python中的数据容器 4.小节总结 63节-列表的定义语法 1.学习目标 2.为什么需要列表&#xff1f; 3.列表定义的基本语法 4.列表定义的基本语法-案例演示 5.列表定义的基本语…

Linux基本指令/下

目录 1.echo、cat与printf 2. > 操作符 与 >> 操作符 3. < 操作符 4.消息传送 linux文件深入 5.文件类型 6.mv命令 7.时间相关指令 8.查找命令 9.grep命令 10.zip/unzip/tar命令 11.scp命令 12.bc命令 13.uname 指令 14.快捷键大全 15.关机/重启/睡…

matlab中绘图函数plot

MATLAB中的plot函数&#xff1a;数据可视化的强大工具 引言 在科学计算和工程领域&#xff0c;数据可视化是理解和分析数据的关键步骤。MATLAB作为一款强大的数值计算软件&#xff0c;提供了丰富的绘图功能&#xff0c;其中plot函数是最基础、最常用的二维图形绘制工具。本文…

在线音乐服务器测试报告

1.项目背景 此项目主要用于模拟市面上主流的音乐软件的主要功能&#xff0c;提高自己的开发和测试能力。此项目采用的技术栈是SpringBoot MyBatis SpringMVC Mysql实现的&#xff0c;为了实现简单&#xff0c;方便测试&#xff0c;此项目没有注册功能&#xff0c;数据提前存…

leetcode-hot-100 (矩阵)

1、矩阵置零 题目链接&#xff1a;矩阵置零 题目描述&#xff1a;给定一个 m x n 的矩阵&#xff0c;如果一个元素为 0 &#xff0c;则将其所在行和列的所有元素都设为 0 。请使用 原地 算法。 解答 方法一&#xff1a;使用一个二维数组 这是我看到这道题目的第一个想法&am…

评标专家系统随机抽选 开发 Excel 中使用东方仙盟软件助理——未来之窗——仙盟创梦IDE

评标专家抽取系统是针对建设项目与采购招投标&#xff0c;从专家库中随机抽取参与评标专家&#xff0c;并自动进行语音通知的管理软件。符合《中华人民共和国招标投标法》及发改委颁布的《评标专家和评标专家库管理暂行办法》&#xff1b;操作简便、保密性强。 软件根据设定抽取…