[算法系列之三十三]杨氏矩阵

简介:

即对于矩阵Table有Table[i][j] ≤Table[i][j + 1], Table[i][j] ≤ Table[i + 1][j],我们也称这样的矩阵为杨氏矩阵。

给出判定某个数是否存在该矩阵中的高效算法。

 

分析:

为了便于复杂度分析,我们暂时假定该矩阵为大小n*n。如下图所示为一个杨氏矩阵。



二分搜索解法:

许多人都观察到了矩阵在二维上都是有序的,所以使用在每一行(或者每一列)使用二分搜索是很自然的想法。由于每一行二分搜索需要O(lgn)时间,搜索n行需要O(nlogn)的时间。显然这个时间复杂度还是不够高效。当然这只是第一步尝试,不要让自己过早的陷入到二分搜索的泥潭中,好的方法还在后面。

 

一种错误的想法:

如果不细心也许会掉入一个陷阱中。有人也许认为可以先从行来判定,如果某个数位于某2行间,则只需要检查相应的2列即可,这是错误的。如下左边图所示,假定我们需要查找9是否在矩阵中,由于9位于7到11之间,所以接下来在7和11的这两列中(这2列在图中高亮显示)二分查找9,虽然能够查找到9,虽然查找9成功了,但是这个方法是错误的。因为10也位于7到11之间,但是10并不在这2列中。

即便是如下右边图示查询范围包括2行2列,尽管在查找9和10都成功,但是还是错误的,反例大家可以自己找一个。

                                           

      

Step-wise线性搜索解法:

从右上角开始,每次将搜索值与右上角的值比较,如果大于右上角的值,则直接去除1行,否则,则去掉1列。如下图显示了查找13的轨迹。首先与右上角15比较,13<15,所以去掉最右1列,然后与11比较,这是13>11,去掉最上面1行…以此类推,最后找到13。算法复杂度O(n),最坏情况需要2n步,即从右上角开始查找,而要查找的目标值在左下角的时候。


【代码】

[cpp]  view plain copy
  1. bool stepWise(int mat[][N_MAX], int N, int target,  
  2.               int &row, int &col) {  
  3.   if (target < mat[0][0] || target > mat[N-1][N-1]) return false;  
  4.   row = 0;  
  5.   col = N-1;  
  6.   while (row <= N-1 && col >= 0) {  
  7.     if (mat[row][col] < target)  
  8.       row++;  
  9.     else if (mat[row][col] > target)  
  10.       col--;  
  11.     else  
  12.       return true;  
  13.   }  
  14.   return false;  
  15. }  


四分分解算法:

通过观察很容易发现该题可以使用分治法来解决。可以看到,矩阵的中间元素总是将矩阵分成了4个子矩阵。如下图所示,中间元素9将矩阵分成了4个小矩阵,这4个小矩阵在行和列上面都是排好序的,所以原问题可以分解为4个子问题。进一步观察可以发现,每次可以排除掉1个子矩阵,也就是说只要考虑3个子问题即可。如查找目标元素为13,则13>9,因为左上角的子矩阵都小于9,所以左上角的子矩阵可以不用再查询,只需要查询剩下的3个子矩阵即可。同理,当查找元素为6时,由于6<9,因为右下角的子矩阵都大于9,因此可以直接排除右下角的子矩阵,只需要查询其他3个子矩阵即可。当然,如果中间元素等于查询的目标元素,则直接返回即可,否则在剩下的3个子矩阵中查询。


该算法代码如下,注意边界条件,代码中加粗的部分不可省略,否则会导致代码不可终止。l==r&&u==d表示矩阵中只有一个元素,此时若不等于目标元素target,则必须返回false。

[cpp]  view plain copy
  1. bool quadPart(int mat[][N_MAX], int M, int N, int target, int l, int u, int r, int d, int &targetRow, int &targetCol) {  
  2.   if (l > r || u > d) return false;  
  3.   if (target < mat[u][l] || target > mat[d][r]) return false;  
  4.   int col = l + (r-l)/2;  
  5.   int row = u + (d-u)/2;  
  6.   if (mat[row][col] == target) {  
  7.     targetRow = row;  
  8.     targetCol = col;  
  9.     return true;  
  10.   } else if (l == r && u == d) {  
  11.     return false;  
  12.   }  
  13.   if (mat[row][col] > target) {  
  14.     return quadPart(mat, M, N, target, col+1, u, r, row, targetRow, targetCol) ||  
  15.            quadPart(mat, M, N, target, l, row+1, col, d, targetRow, targetCol) ||  
  16.            quadPart(mat, M, N, target, l, u, col, row, targetRow, targetCol);  
  17.   } else {  
  18.     return quadPart(mat, M, N, target, col+1, u, r, row, targetRow, targetCol) ||  
  19.            quadPart(mat, M, N, target, l, row+1, col, d, targetRow, targetCol) ||  
  20.            quadPart(mat, M, N, target, col+1, row+1, r, d, targetRow, targetCol);  
  21.   }  
  22. }  
  23.    
  24. bool quadPart(int mat[][N_MAX], int N, int target, int &row, int &col) {  
  25.   return quadPart(mat, N, N, target, 0, 0, N-1, N-1, row, col);  
  26. }  


该算法复杂度是多少呢?可以通过公式计算:

原文公式: T(n) = 3T(n/2) + c, 
T(n) = 3T(n/2) + c      = 3 [ 3T(n/4) + c ] + c       = 3 [ 3 [ 3T(n/8)  + c ] + c ] + c      = 3k T(n/2k) + c (3k - 1)/2   = 3k ( T(n/2k) + c ) - c/2 Setting k = lg n,  T(n)  = 3lg n ( T(1) + c ) - c/2       = O(3lg n)       = O(nlg 3)          <== 3lg n = nlg 3       = O(n1.58
注:我以为这里公式应该是T(n) = 3 * T(n/4) + c ,不对的话请大家指正。



二分算法

这个算法我们从矩阵中间行或者中间列或者对角线开始查找,找到s满足

 ai < s < ai+1 ,  其中ai为矩阵中的值。


a)从中间行查找,如查找10位于9到16之间。


b)从中间列查找,如查找10位于9到14之间。


c)从对角线查找,查找10位于9到17之间。

显然不管从哪里查找,都可以将原矩阵分成2个子矩阵,这样就分成了2个子问题,比起四分分解法的3个子问题,这个方法应该更好。

代码如下,注意这里代码确定范围用的是线性查找,实际可以通过二分查找加速整个过程。

[cpp]  view plain copy
  1. bool binPart(int mat[][N_MAX], int M, int N, int target, int l, int u, int r, int d, int &targetRow, int &targetCol) {  
  2.   if (l > r || u > d) return false;  
  3.   if (target < mat[u][l] || target > mat[d][r]) return false;  
  4.   int mid = l + (r-l)/2;  
  5.   int row = u;  
  6.   while (row <= d && mat[row][mid] <= target) {  
  7.     if (mat[row][mid] == target) {  
  8.       targetRow = row;  
  9.       targetCol = mid;  
  10.       return true;  
  11.     }  
  12.     row++;  
  13.   }  
  14.   return binPart(mat, M, N, target, mid+1, u, r, row-1, targetRow, targetCol) ||  
  15.          binPart(mat, M, N, target, l, row, mid-1, d, targetRow, targetCol);  
  16. }  
  17.    
  18. bool binPart(int mat[][N_MAX], int N, int target, int &row, int &col) {  
  19.   return binPart(mat, N, N, target, 0, 0, N-1, N-1, row, col);  
  20. }  

该方法复杂度的分析:为了方便,假定最后查找的子矩阵为分成了2个相同大小的子矩阵,且都为原来1/4大小。

T(n) = 2T(n/4)+cn 

如果采用二分查找确定范围,则T(n)=2T(n/4)+clgn

英文原文地址:http://www.leetcode.com/2010/10/searching-2d-sorted-matrix-part-ii.html


目录
打赏
0
0
0
0
63
分享
相关文章
【算法题目解析】杨氏矩阵数字查找
一道面试时可能遇到的算法问题,杨氏矩阵。可以重点关注思考方式,而不是死记硬背。
95 0
算法篇-杨氏矩阵
算法篇-杨氏矩阵
126 0
基于和声搜索优化算法的机器工作调度matlab仿真,输出甘特图
本程序基于和声搜索优化算法(Harmony Search, HS),实现机器工作调度的MATLAB仿真,输出甘特图展示调度结果。算法通过模拟音乐家即兴演奏寻找最佳和声的过程,优化任务在不同机器上的执行顺序,以最小化完成时间和最大化资源利用率为目标。程序适用于MATLAB 2022A版本,运行后无水印。核心参数包括和声记忆大小(HMS)等,适应度函数用于建模优化目标。附带完整代码与运行结果展示。
基于AES的遥感图像加密算法matlab仿真
本程序基于MATLAB 2022a实现,采用AES算法对遥感图像进行加密与解密。主要步骤包括:将彩色图像灰度化并重置大小为256×256像素,通过AES的字节替换、行移位、列混合及轮密钥加等操作完成加密,随后进行解密并验证图像质量(如PSNR值)。实验结果展示了原图、加密图和解密图,分析了图像直方图、相关性及熵的变化,确保加密安全性与解密后图像质量。该方法适用于保护遥感图像中的敏感信息,在军事、环境监测等领域具有重要应用价值。
基于免疫算法的最优物流仓储点选址方案MATLAB仿真
本程序基于免疫算法实现物流仓储点选址优化,并通过MATLAB 2022A仿真展示结果。核心代码包括收敛曲线绘制、最优派送路线规划及可视化。算法模拟生物免疫系统,通过多样性生成、亲和力评价、选择、克隆、变异和抑制机制,高效搜索最优解。解决了物流仓储点选址这一复杂多目标优化问题,显著提升物流效率与服务质量。附完整无水印运行结果图示。
基于免疫算法的最优物流仓储点选址方案MATLAB仿真
基于GA遗传优化TCN-GRU时间卷积神经网络时间序列预测算法matlab仿真
本项目基于MATLAB2022a开发,提供无水印算法运行效果预览及核心程序(含详细中文注释与操作视频)。通过结合时间卷积神经网络(TCN)和遗传算法(GA),实现复杂非线性时间序列的高精度预测。TCN利用因果卷积层与残差连接提取时间特征,GA优化超参数(如卷积核大小、层数等),显著提升模型性能。项目涵盖理论概述、程序代码及完整实现流程,适用于金融、气象、工业等领域的时间序列预测任务。
基于遗传优化算法的多AGV栅格地图路径规划matlab仿真
本程序基于遗传优化算法实现多AGV栅格地图路径规划的MATLAB仿真(测试版本:MATLAB2022A)。支持单个及多个AGV路径规划,输出路径结果与收敛曲线。核心程序代码完整,无水印。算法适用于现代工业与物流场景,通过模拟自然进化机制(选择、交叉、变异)解决复杂环境下的路径优化问题,有效提升效率并避免碰撞。适合学习研究多AGV系统路径规划技术。
基于GA遗传算法的斜拉桥静载试验车辆最优布载matlab仿真
本程序基于遗传算法(GA)实现斜拉桥静载试验车辆最优布载的MATLAB仿真,旨在自动化确定车辆位置以满足加载效率ηq(0.95≤ηq≤1.05)的要求,目标是使ηq尽量接近1,同时减少加载车辆数量和布载耗时。程序通过迭代优化计算车辆位置、方向、类型及占用车道等参数,并展示适应度值收敛过程。测试版本为MATLAB2022A,包含核心代码与运行结果展示。优化模型综合考虑车辆总重量、间距及桥梁允许载荷密度等约束条件,确保布载方案科学合理。
基于ECC簇内分组密钥管理算法的无线传感器网络matlab性能仿真
本程序基于ECC(椭圆曲线密码学)簇内分组密钥管理算法,对无线传感器网络(WSN)进行MATLAB性能仿真。通过对比网络通信开销、存活节点数量、网络能耗及数据通信量四个关键指标,验证算法的高效性和安全性。程序在MATLAB 2022A版本下运行,结果无水印展示。算法通过将WSN划分为多个簇,利用ECC生成和分发密钥,降低计算与通信成本,适用于资源受限的传感器网络场景,确保数据保密性和完整性。
基于GA遗传优化TCN时间卷积神经网络时间序列预测算法matlab仿真
本内容介绍了一种基于遗传算法优化的时间卷积神经网络(TCN)用于时间序列预测的方法。算法运行于 Matlab2022a,完整程序无水印,附带核心代码、中文注释及操作视频。TCN通过因果卷积层与残差连接学习时间序列复杂特征,但其性能依赖超参数设置。遗传算法通过对种群迭代优化,确定最佳超参数组合,提升预测精度。此方法适用于金融、气象等领域,实现更准确可靠的未来趋势预测。
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等