在二维矩阵/数组中查找元素 Leetcode74, Leetcode240

这一类题型中二维数组的元素取值有序变化,因此可以用二分查找法。我们一起来看一下。

一、Leetcode 74

Leetcode 74. 搜索二维矩阵 这道题要在一个二维矩阵中查找元素。该二维矩阵有如下特点:

  • 每行元素 从左到右 按非递减顺序排列。
  • 每行的第一个元素 > 前一行的最后一个元素。

也就是说,这种二维数组的元素逐行、逐列递增变化,如下图所示,沿箭头方向元素值递增:

方法一:做两次二分查找。
  • 先在第一列中查找值为 target 的元素所在行。
  • 再在这一行中查找值为 target 的元素所在列。

在这两步中,难点在于第一步确定 target 所在行。以图中的示例矩阵为例,要寻找 3,如何定位到 3 所在行呢?在第一列的元素中,3 所在行的第一列元素 1 是小于 3 的元素中最接近 3 的元素,这就是第一步的思路:在第一列元素中查找小于等于 target、且最接近 target 的元素。这里可以用 Leetcode 69 所使用的方法(欢迎阅读文章:二分查找法搜寻元素 Leetcode35, Leetcode69,其中详细介绍了这类问题的两种解决方法,本文采用了其中一种方法。)

相应的 Python 代码和注释为:

python 复制代码
class Solution:
    def searchMatrix(self, matrix: List[List[int]], target: int) -> bool:
        # 第一步:查找元素所在行
        low, high = 0, len(matrix) - 1
        while low <= high:
            mid = low + (high - low) // 2
            # 注意:这里是在第 1 列查找,
            # mid元素索引为 matrix[mid][0]。
            if matrix[mid][0] == target:
                return True
            elif matrix[mid][0] > target:
                high = mid - 1
            else:
                low = mid + 1
        # 确定元素所在行(row)
        row = high

        # 第二步:查找元素所在列
        low, high = 0, len(matrix[0]) - 1
        while low <= high:
            mid = low + (high - low) // 2
            # 注意:这里是在第 row 行查找,
            # mid元素索引为 matrix[row][mid]。
            if matrix[row][mid] == target:
                return True
            elif matrix[row][mid] > target:
                high = mid - 1
            else:
                low = mid + 1

        return False         
方法二:把二维矩阵看作一个一维数组处理。

因为矩阵的元素是按升序排列,我们在处理时可以把它想象成连续的一维序列,就像上图示例矩阵中的元素,在脑子里把它"拼接"成一个连续的一维数组,[1,3,5,7,10,11,16,20,23,30,34,60],在这个升序数组里查找元素很容易。

但是,这个一维数组索引只是我们为了解决问题做的设想,实际中矩阵元素是以二维数组形式存储的,因此每次索引元素值时还需要一个操作:把(设想的)一维数组索引换算回(实际的)二维数组索引。

相应的 Python 代码和注释为:

python 复制代码
class Solution:
    def searchMatrix(self, matrix: List[List[int]], target: int) -> bool:
        # 求 mxn 矩阵的维度大小
        m = len(matrix)
        n = len(matrix[0])
        
        # 按"一维"有序数组处理
        length = m*n
        low, high = 0, length - 1
        while low <= high:
            mid = low + (high - low) // 2
            
            # 关键:索引时要把(设想的)一维数组索引换算回(实际的)二维数组索引。
            mid_row = mid // n
            mid_col = mid % n
            mid_val = matrix[mid_row][mid_col] 
            
            if mid_val == target:
                return True
            elif mid_val > target:
                high = mid - 1
            else:
                low = mid + 1
        return False           

方法二实现起来比方法一更简洁,但是我在 Leetcode 运行代码时发现方法二比方法一的耗时大。

二、Leetcode 240

Leetcode 240. 搜索二维矩阵 II 这道题也是在二维矩阵中查找元素。不同的是,这里的二维矩阵有如下特点:

  • 每行的元素 从左到右 升序排列。
  • 每列的元素 从上到下 升序排列。

下图所示为一个示例矩阵:

这道题的巧妙之处在于中点 mid 的选择

根据给定矩阵的升序排列特点,一个元素位于第 i 行、第 j 列,则该元素所在行第 0 ~ ( j - 1 ) 列的元素都比它小;该元素所在列第 ( i + 1 ) ~ ( m - 1 ) 行的元素都比它大。具体来说,以上图的示例矩阵为例,如绿色箭头标识所示,以圆圈中的元素 8 为中点,[ 2, 5, 8, 9, 14, 23 ] 这些元素就构成了一个升序排列的数组。也就是说,以第 i 行、第 j 列的元素为直角,其所在行和列元素构成的 倒 "L" 形状序列 是一个有序数组,而在直角的这个元素就是数组的中点。在这个数组中可以用二分查找:比较中点的元素与目标值 target 的大小决定下一步的寻找范围。如果该元素大于 target,就往左移一列:j - 1。如果该元素小于 target,就往下移一行:i + 1。

应该从哪里开始呢?选择右上角的元素(第 0 行,(n-1) 列)做为起始 mid 元素,逐步推进到左下角元素。时间复杂度是 O(m+n)。这一点您可以试一下,如果要找的元素位于左下角,正好要走 m+ n 步。

相应的 Python 代码为:

python 复制代码
class Solution:
    def searchMatrix(self, matrix: List[List[int]], target: int) -> bool:
        m, n = len(matrix), len(matrix[0])
        i, j = 0, n - 1
        while i < m and j >= 0:
            if matrix[i][j] == target:
                return True
            elif matrix[i][j] > target:
                j -= 1
            else:
                i += 1
        return False             

本文对您有帮助的话,请点赞支持一下吧,谢谢!

关注我 宁萌Julie,互相学习,多多交流呀!

参考

1.Leetcode 74 方法二思路:Don't treat it as a 2D matrix, just treat it as a sorted list - Search a 2D Matrix - LeetCode

2.Leetcode 240 思路:My concise O(m+n) Java solution - Search a 2D Matrix II - LeetCode

相关推荐
资深web全栈开发3 小时前
LeetCode 3625. 统计梯形的数目 II
算法·leetcode·组合数学
橘颂TA3 小时前
【剑斩OFFER】算法的暴力美学——外观数列
算法·leetcode·职场和发展·结构与算法
Liangwei Lin3 小时前
洛谷 P1434 [SHOI2002] 滑雪
算法
c#上位机4 小时前
halcon图像增强之自动灰度拉伸
图像处理·算法·c#·halcon·图像增强
rit84324994 小时前
压缩感知信号恢复算法:OMP与CoSaMP对比分析
数据库·人工智能·算法
Pluchon5 小时前
硅基计划4.0 算法 FloodFill算法
java·算法·leetcode·决策树·逻辑回归·深度优先·图搜索算法
菜鸟233号5 小时前
力扣347. 前k个高频元素 java实现
算法
小许学java5 小时前
数据结构-模拟实现顺序表和链表
java·数据结构·链表·arraylist·linkedlist·顺序表模拟实现·链表的模拟实现
Xの哲學6 小时前
Linux设备管理:从内核驱动到用户空间的完整架构解析
linux·服务器·算法·架构·边缘计算
xinyu_Jina6 小时前
Info Flow:去中心化数据流、跨协议标准化与信息源权重算法
算法·去中心化·区块链