算法题解记录18+++搜索二维矩阵Ⅱ

本题可以说是运用二分查找的典例,即使是面对矩阵,只要是它保持"排序好"这样的结构,就一定能采用二分查找法。【你知道的,对于排序好的数组,二分查找几乎是最优秀的算法】

当然,答案提供的是"Z字形查找法"【这个概念我搜不到,不过其实质,就是矩阵边界的缩减】

"Z字形"排查效率高于二分查找法,只是因为题目结构特殊,一般不会有这种结构。

题目描述:

编写一个高效的算法来搜索 m xn 矩阵 matrix 中的一个目标值 target 。该矩阵具有以下特性:

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

示例 1:

复制代码
输入:matrix = [[1,4,7,11,15],[2,5,8,12,19],[3,6,9,16,22],[10,13,14,17,24],[18,21,23,26,30]], target = 5
输出:true

示例 2:

复制代码
输入:matrix = [[1,4,7,11,15],[2,5,8,12,19],[3,6,9,16,22],[10,13,14,17,24],[18,21,23,26,30]], target = 20
输出:false

提示:

  • m == matrix.length
  • n == matrix[i].length
  • 1 <= n, m <= 300
  • -10^9 <= matrix[i][j] <= 10^9
  • 每行的所有元素从左到右升序排列
  • 每列的所有元素从上到下升序排列
  • -10^9 <= target <= 10^9

解题准备:

1.理解题意:本题的结构,非常特殊,对于matrix中的任一元素【i,j】,其具备四个属性,上、左的元素小于它,下、右的元素大于它【对于边界元素不讨论,类似】

2.理解可能具备的操作:就此,大概率只需要查找一种操作即可。

3.朴素的思路:对于矩阵,最简单的遍历原则就是,暴力遍历【从0行到len-1行,从0列到len2-1列,依次遍历元素】

代码为:

for(int i=0; i<m; i++){
    for(int j=0; j<n; j++){
        // m是行数,n是列数。
        // 在这个语句段里操作
    }
}

不过,虽然这样做,一定能找到target(或者发现根本没有),却浪费了约束条件:每一行、列存在递增的关系。

解题难点1分析:

如果不从二分查找的角度,对于这种结构比较容易想到的优化方法为:

1.遍历第0行的元素,依次判断大小(如果< target,+1),如果等于target直接返回true,如果大于target说明这一行不可能存在target,遍历下一行。

2.接着上述,遍历第1行,同理......

问题:时间复杂度仍高

对于这种优化方案,如果是下图的结构:

容易发现,其遍历次数与暴力for一样多,所以时间复杂度的优化很差。

就算是一般的结构,如果target比较大,很大概率前面k行,也得全部遍历(k随机),也就是说,时间复杂度没怎么优化。从最差优化的角度分析,时间复杂度仍是O(m*n);

没办法,这种优化不可取,得从别的角度出发。

解题难点2分析:

从二分查找的角度出发,既然行列间满足递增的约束,那么对于每一行,必然也满足递增的约束。

拆分每一行,拆成0到len-1行,每一行用二分查找查找,时间复杂度为O(logN)。

由于遍历0到len-1行,所以总的时间复杂度是O(m * log n);

代码在此不写了,比较简单。

不过,这道题是个强约束,拆分后,反而增加了查找时间复杂度。

解题难点3分析:

从结构本身出发,由于行列间递增,那么,应该能处理特殊的数据。

什么意思呢?我们用【0,0】,【0,len-1】,【len2-1,0】,【len-1,len2-1】维护矩阵的四个角的数据。

由于矩阵的特殊性质,我们知道:【0,0】一定是最小的,【0,len-1】一定是0行最大的,【len2-1,0】一定是0列最大的,【len-1, len2-1】一定是所有数据最大的。

如果矩阵中存在target,那么它一定大于【0,0】,小于【len-1,len2-1】。

如果target大于【0, len-1】呢?这说明,target大于0行所有元素,那需要继续查找0行吗?

可以直接忽略,从第1行开始查找。

不过,target可能小于【0, len-1】,同时大于【0, 0】,这说明它可能在第0行。

这时候从【len2-1, 0】开始判断,问题又来了:可能target同时大于【0,0】,小于【len2-1,0】

不过,如果target小于【len2-1, 0】,不就说明:第len2-1行,都比target大吗?(因为【len2-1,0】在该行最小)

那么,往上移动一行,不就行了?

其实从这个角度,看【0, len-1】也一样,如果target小于【0,len-1】,不就说明target小于len-1列的所有元素吗?

往回退一列,不就行了?

为了保持一致性,建议在四个角中,拿一个元素操作即可。

该算法,每次可以排除一行或者一列,效率更高一些。

以上内容即我想分享的关于力扣热题18的一些知识。

我是蚊子码农,如有补充,欢迎在评论区留言。个人也是初学者,知识体系可能没有那么完善,希望各位多多指正,谢谢大家。

相关推荐
VertexGeek23 分钟前
Rust学习(八):异常处理和宏编程:
学习·算法·rust
石小石Orz23 分钟前
Three.js + AI:AI 算法生成 3D 萤火虫飞舞效果~
javascript·人工智能·算法
jiao_mrswang1 小时前
leetcode-18-四数之和
算法·leetcode·职场和发展
qystca1 小时前
洛谷 B3637 最长上升子序列 C语言 记忆化搜索->‘正序‘dp
c语言·开发语言·算法
薯条不要番茄酱1 小时前
数据结构-8.Java. 七大排序算法(中篇)
java·开发语言·数据结构·后端·算法·排序算法·intellij-idea
今天吃饺子1 小时前
2024年SCI一区最新改进优化算法——四参数自适应生长优化器,MATLAB代码免费获取...
开发语言·算法·matlab
是阿建吖!2 小时前
【优选算法】二分查找
c++·算法
王燕龙(大卫)2 小时前
leetcode 数组中第k个最大元素
算法·leetcode
不去幼儿园2 小时前
【MARL】深入理解多智能体近端策略优化(MAPPO)算法与调参
人工智能·python·算法·机器学习·强化学习
Mr_Xuhhh3 小时前
重生之我在学环境变量
linux·运维·服务器·前端·chrome·算法