二维数组搜索:从暴力地毯到二分神技的奇幻之旅

二维数组搜索:从暴力地毯到二分神技的奇幻之旅 🔍🚀

面试官:"在有序矩阵里找出 target!"

你:😎 "循环遍历?小菜一碟!"

面试官:"要求时间复杂度低于 O(mn)。"

你:🤯 "稍等...我需要召唤位面之力!"

稳住! 这篇带你通关二维迷宫,从"「人肉扫描仪」进化成「二分法魔神」,全程梗王附体+代码玩梗,包你笑着拿下 offer!👇


核心问题:搜索二维矩阵

题目 :给定一个 m x n 矩阵,满足:

1️⃣ 每行从左到右非严格递增 (允许重复数字)

2️⃣ 每行首个数字 > 上一行最后一个数字

找出目标值 target 是否存在


心路历程:从青铜到王者的进化

1. 暴力双循环:老实人的地毯搜查 ️‍♂️

刚看到题目嘴角上扬:两重循环直接梭哈!

口号 :"管他有序无序,老子逐个掀桌查!" 只要我循环得够快,Offer 就追不上我!

思路

  1. 遍历每一行
  2. 每行再遍历每一列
  3. 找到目标返回 true,否则返回 false

无语时刻

  • 时间复杂度:O(mn),最坏情况遍历整个矩阵
  • 空间复杂度:O(1),只需要常数级额外空间
java 复制代码
class Solution {  
    public boolean searchMatrix(int[][] matrix, int target) {  
        for (int i = 0; i < matrix.length; i++) {  
            for (int j = 0; j < matrix[0].length; j++) {  
                if (matrix[i][j] == target) return true; // 找到!拍桌狂喜 → 发现面试官冷笑  😶🌫️    
            }  
        }  
        return false; // 没找到,默默流泪  💔  
    }  
}  

真相时刻

优点 缺点
✅ 逻辑简单如喝水 ❌ 数据量 >1000?电脑风扇秒变轰炸机!✈️
✅ 空间 O(1) 省内存 ❌ 时间 O(mn) → 万级数据直接卡成PPT 💥

面试官冷笑:"这算法...是用我 CPU 煎蛋?" 🍳


2. 压缩数组法:空间换时间的土豪 💸

口号:"降维打击!二维压成一维再二分!" 把矩阵拉成一条数组 👇

思路

  1. 先计算出总元素个数 m * n
  2. 创建一个新数组 combined,长度为 m * n
  3. 遍历二维数组,将每个元素按行优先顺序放入 combined
  4. combined 数组进行二分查找
  5. 如果找到目标返回 true,否则返回 false

氪金时刻

  • 时间复杂度:O(mn)
    • 转化二维数组的时候时间复杂度是 O(mn),二分查找的时间复杂度是 O(log(mn)),所以总的时间复杂度是 O(mn)
  • 空间复杂度:O(mn) ,需要额外的 combined 数组
java 复制代码
class Solution {  
    public boolean searchMatrix(int[][] matrix, int target) {  
        int m = matrix.length, n = matrix[0].length;  
        int[] combined = new int[m * n]; // 土豪行为:开新数组!  
          
        // 二维坐标 → 一维索引(行优先公式:k = i*n + j)  
        for (int i = 0; i < m; i++) {  
            for (int j = 0; j < n; j++) {  
                combined[i * n + j] = matrix[i][j]; // 二维搬家 📦  
            }  
        }  
        // 一维数组直接二分查找!  
        int index = Arrays.binarySearch(combined, target);  
        return index >= 0;  
    }  
}  

氪金分析

操作 特效 代价
开新数组 内存爆炸金色传说 💥 空间 O(mn) 💸
二分查找 紫色速度光环 ⚡ 时间 O(log(mn))

氪金避坑指南

1️⃣ 内存爆炸 :当 m*n=10^6 时,直接吃掉 4GB内存 💥

2️⃣ 时间陷阱 :数组拷贝耗时 O(mn) ,实际比暴力还慢 🐢

3️⃣ 嘲讽防御:面试官问"空间复杂度?"时,大声回答:"钱能解决的问题都不是问题!" 💰🙃

面试官扶额:"这内存...是用我钱包买的?" 👛 → 下一秒拒信发邮箱 ✉️💣


3. 二分查找神技:时空双省的位面之子

顿悟 :既然数组是有序的,那就不用进行压缩,直接利用数学特性抽象的转化成一维数组,二维当一维用!不用真实的转化,利用有序特性直接映射坐标,那就可以用二分查找!

思路

  1. 先计算出总元素个数 m * n
  2. 定义左右指针 left = 0right = m * n - 1
  3. 进入二分循环,直到 left > right
  4. 计算中间索引 mid = left + (right - left) / 2
  5. mid 映射回二维坐标 (mid/n, mid%n)
  6. 比较 matrix[mid/n][mid%n] 与目标值 target
  7. 如果相等,返回 true

核心公式

  • 一维索引 mid → 二维坐标 (mid/n, mid%n)
  • 二维坐标 (i, j) → 一维索引 k = i*n + j 所以已知 kij
    • i = k / n
    • j = k % n

封神理由

  • 时间 O(log(mn)) → 比一维二分还快?
  • 空间 O(1) → 只用 3 个变量,内存笑开花 😄
  • 不改原数组 → 面试官狂喜!
java 复制代码
class Solution {  
    public boolean searchMatrix(int[][] matrix, int target) {  
        int m = matrix.length, n = matrix[0].length;  
        int left = 0, right = m * n - 1; // 虚拟一维数组的首尾  
          
        while (left <= right) {  
            int mid = left + (right - left) / 2;  
            int midVal = matrix[mid / n][mid % n]; // 魔法坐标转换!✨  
              
            if (midVal == target) return true; // 欧皇一击命中  🎯  
            else if (midVal < target) left = mid + 1; // 向右半区突进 →  
            else right = mid - 1; // 向左半区后撤 ←  
        }  
        return false;  
    }  
}  

面试官震惊:"这思路...是开挂了吧?" 🤯 → 当场掏出劳动合同 ✍️💰


4. 双指针巡查:优雅的矩阵猎人

口号:"从右上角开始,遇小下移,遇大左移!"

思路

  1. 从右上角开始
  2. 如果当前元素等于目标,返回 true
  3. 如果当前元素小于目标,下移
  4. 如果当前元素大于目标,左移
  5. 如果超出边界,返回 false

代码简洁,优雅

时间复杂度O(m + n) ,最坏情况遍历全表,但是成功将时间复杂度降到了 O(m + n)常数级,无疑是一个重大意义的突破

空间复杂度O(1),只需要常数级额外空间

java 复制代码
class Solution {  
    public boolean searchMatrix(int[][] matrix, int target) {  
        int row = 0, col = matrix[0].length - 1; // 定位右上角    
          
        while (row < matrix.length && col >= 0) {  
            if (matrix[row][col] == target) return true; // 逮到!  
            else if (matrix[row][col] < target) row++; // 目标更大→下移  👇  
            else col--; // 目标更小→左移  👈  
        }  
        return false;  
    }  
}  

巡查指南

当前位置 vs Target 行动 方向
等于 收工撒花 🎉 -
小于 下移找更大 ⬇️ 抛弃当前行
大于 左移找更小 ️ 抛弃当前列

灵魂拷问:"如果无序怎么办?" 面试官阴险一笑 😏

无序矩阵?这套路照样浪到飞起! 🌊


5. 分行二分法:学院派de精确制导

策略:先二分定位行,再二分定位列

思路

  1. 先二分查找行
  2. 找到目标行
  3. 在目标行进行二分查找
  4. 如果找到目标,返回 true,否则返回 false

代码清晰,逻辑严谨!
时间复杂度O(log m + log n),因为每次二分都将搜索空间减半,我的妈呀,这直接优化的更快更迅捷了

空间复杂度O(1),只需要常数级额外空间

java 复制代码
class Solution {  
    public boolean searchMatrix(int[][] matrix, int target) {  
        int m = matrix.length, n = matrix[0].length;  
        // Step 1: 二分锁定行(找最后一个 matrix[i][0] <= target 的行)  
        int top = 0, bottom = m - 1;  
        while (top <= bottom) {  
            int midRow = top + (bottom - top) / 2;  
            if (matrix[midRow][0] == target) return true;  
            else if (matrix[midRow][0] < target) top = midRow + 1;  
            else bottom = midRow - 1;  
        }  
        if (bottom < 0) return false; // target 比所有数都小  
          
        // Step 2: 在目标行 binarySearch  
        int left = 0, right = n - 1;  
        int[] targetRow = matrix[bottom];  
        while (left <= right) {  
            int mid = left + (right - left) / 2;  
            if (targetRow[mid] == target) return true;  
            else if (targetRow[mid] < target) left = mid + 1;  
            else right = mid - 1;  
        }  
        return false;  
    }  
}  

适用场景

  • 需分别获取行列位置时
  • 面试官要求"显式分步操作"

面试官:"这思路...你明天能来上班吗?" 😲

你:"薪资 double 的话,现在就能签合同!" ✍️💰


🔥 终极大乱斗:解法性能 PK 台

解法 时间复杂度 空间复杂度 优点 缺点
暴力双循环 🔄 O(mn) O(1) 代码直白 慢如乌龟
压缩数组法 💾 O(log(mn)) O(mn) 思路简单 内存爆炸 💥
二分神技 O(log(mn)) O(1) 时空双优 坐标转换需理解
双指针巡查 O(m + n) O(1) 代码优雅 最坏情况遍历全表
分行二分法 🎓 O(log m + log n) O(1) 分步清晰 代码略长

彩蛋:无序矩阵怎么搜?

面试官阴笑 :"如果行和列各自递增,但整体无序呢?" (这在拓展里直接解决) 答案

1️⃣ 暴力循环:删库跑路前の挣扎 ♂️💨

2️⃣ 贪吃蛇升级版:照样从右上角开溜! 🐍💨 (双指针)

java 复制代码
while (row < matrix.length && col >= 0) { ... } // 代码不改,嚣张依旧  😎  

原理

  • 行从左→右递增 → 列可收缩
  • 列从上→下递增 → 行可收缩
    面试官:"这波操作...我裂开了啊!" 🤯

彩蛋 搜索二维矩阵 II

题目升级 :每行从左到右升序,每列从上到下升序,但 失去"行首 > 上行尾"特性

依旧是万能的暴力解决法,代码甚至不需要改动,原版直接写

名场面 :当面试官掏出 10^6 级无序矩阵,你的暴力代码直接触发电脑煎蛋模式🍳→机箱飘出烤面包香气🤯

java 复制代码
class Solution {
    public boolean searchMatrix(int[][] matrix, int target) {
        int m = matrix.length;
        int n = matrix[0].length;

        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (matrix[i][j] == target) return true;
            }
        }

        return false;
    }
}

地狱级暴雷三连

1️⃣ 时间复杂度 O(mn) :万级数据?等结果时够打完三局王者🍜

2️⃣ 稀疏矩阵噩梦 :99%空值?照样憨憨遍历到地老天荒⏳

3️⃣ 面试官补刀:"还能优化吗?" → 你:"...我选择删库跑路💨"

适用场景

  • 面试想提前结束🙏
  • 给电脑煎蛋当借口🍳

双指针贪吃蛇2.0:无序矩阵的救世主

走位原理

行从左→右递增 → 列=贪吃蛇通道 "右边永远比左边胖"

列从上→下递增 → 行=滑滑梯 "楼下永远比楼上香" 🛝

java 复制代码
class Solution {  
    public boolean searchMatrix(int[][] matrix, int target) {  
        int row = 0, col = matrix[0].length - 1; // 坚守右上角起点!  
        while (row < matrix.length && col >= 0) {  
            if (matrix[row][col] == target) return true;  
            else if (matrix[row][col] < target) row++; // 目标更大→下移  👇  
            else col--; // 目标更小→左移 👈  
        }  
        return false;  
    }  
}  

为何仍有效

  • ✅ 每行从左到右递增 → 列方向可收缩
  • ✅ 每列从上到下递增 → 行方向可收缩

🤓 分行二分法:学院派de精确制导

灵魂暴击 :当双指针被问复杂度?秒切分行二分!
操作流

1️⃣ 行二分 :锁定 matrix[i][0] ≤ target 的最后一行 🔍

2️⃣ 列二分:在目标行玩一维数组二分 🎯

java 复制代码
class Solution {
    public boolean searchMatrix(int[][] matrix, int target) {
        int m = matrix.length;
        int n = matrix[0].length;

        for (int i = 0; i < m; i++) {
            int left = 0, right = n - 1;
            while (left <= right) {
                int mid = left + (right - left) / 2;
                if (matrix[i][mid] == target) {
                    return true; 
                } else if (matrix[i][mid] < target) {
                    left = mid + 1;
                } else {
                    right = mid - 1;
                } 

            }  

        } 

        return false;
    } 
}

为什么封神

  • 时间 O(log m + log n) → 比降维二分更快?玄学时刻!🌀
  • 显式分步 → 面试官想挑刺都无从下手👓
  • 避免坐标转换 → 数学苦手の救星🎓

致命缺陷

失去全局有序性 → 每行必须独立二分!否则直接翻车💥


💣 三大解法的修罗场:卷王争霸赛开战!

根据文档1的硬核对比,240题解法新增骚气评价👇

解法 名场面 杀伤力 梗王评级
暴力循环 电脑煎蛋声滋滋响 🍳 伤敌0自损10086 🤦♂️《自爆卡车》
二分分行 if-else套娃写到手抽筋 ✍️ 精准但龟速 🧠《学院派の强迫症》
双指针 矩阵里走出六亲不认の魔鬼步伐 👾 时空双优+代码短 🐍《贪吃蛇の速度与激情》

无限大の编程哲学

"从 O(mn) 暴力到 O(log(mn)) 二分,就像人生------
找准坐标映射,降维打击难题,offer 自会降临!" 🚀

相关推荐
字节逆旅1 小时前
从一次爬坑看前端的出路
前端·后端·程序员
Chan162 小时前
【智能协同云图库】第七期:基于AI调用阿里云百炼大模型,实现AI图片编辑功能
java·人工智能·spring boot·后端·spring·ai·ai作画
mitt_2 小时前
go语言变量
开发语言·后端·golang
bobz9653 小时前
最近玩了好多把 LOL
后端
爱欲无极3 小时前
基于Flask的微博话题多标签情感分析系统设计
后端·python·flask
cwkiller3 小时前
heapdump深度利用之信息泄露篇
后端
Olrookie6 小时前
若依前后端分离版学习笔记(五)——Spring Boot简介与Spring Security
笔记·后端·学习·spring·ruoyi
小白的代码日记6 小时前
基于 Spring Boot 的小区人脸识别与出入记录管理系统实现
java·spring boot·后端
Chaney不会代码6 小时前
Java7/8中的HashMap深挖
后端