一、题目简述
使用高效算法搜索 m×n 矩阵中是否存在某个数字,且该矩阵存在如下性质:
1. 每行中的数字从左到右依次递增。
2. 每列中的数字从上到下依次递增。示例:给定如下矩阵,
⎡⎣⎢⎢⎢⎢⎢⎢12310184561321789142311121617261519222430⎤⎦⎥⎥⎥⎥⎥⎥
给定 target=5 , return true
给定 target=20 , return false
二、编程思路
由于题目所给的矩阵具有行列有序的性质,因此可以使用类似二分查找的方法寻找矩阵中的数值。
⎡⎣⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢(ltx,lty)⋮⋯⋯(mx+1,lty)⋮⋯⋯⋱⋯⋯⋯⋱⋯⋯⋮(mx−1,my−1)⋯⋯⋮(rbx,my−1)⋮⋮⋮(mx,my)⋮⋮⋮(ltx,my+1)⋮⋯⋯(mx+1,my+1)⋮⋯⋯⋱⋯⋯⋯⋱⋯⋯⋮(mx−1,rby)⋯⋯⋮(rbx,rby)⎤⎦⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥
使用矩阵的左上角坐标 (ltx,lty) 和右下角坐标 (rbx,rby) 表示矩阵, (mx,my) 表示矩阵中心点的坐标。
递归基:若中心点与左上角点重合,则对整个矩阵进行搜索。
递归步:
- 若 target 大于中心点元素,则搜索 除左上角矩阵的其他三个矩阵;
- 若 target 小于中心点元素,则搜索 除右上角矩阵的其他三个矩阵;
- 若相同,则返回 true
注意:
- 矩阵越界情况的检查及矩阵行、列数为0的特殊情况;
- 矩阵边界的确定。
三、代码设计
class Solution {
public:
bool searchMatrix(vector<vector<int>>& matrix, int target) {
//特殊情况检查
if (matrix.size() == 0 || matrix[0].size() == 0) return false;
int ltx, lty, rbx, rby, mx, my;
ltx = 0; lty = 0; rbx = matrix.size()-1; rby = matrix[0].size()-1;
return searchSmallMatrix(matrix, target, ltx, lty, rbx, rby);
}
bool searchSmallMatrix(vector<vector<int>>& matrix,int target,int ltx, int lty, int rbx, int rby){
//定义递归基
int w, h;
w = matrix.size();
h = matrix[0].size();
if (ltx < 0 | lty < 0 | rbx < 0 | rby < 0) return false;
if (ltx >= w | rbx >= w | lty >= h | rby >= h) return false;
//cout << ltx << " " << lty << " " << rbx << " " << rby << endl;
int mx, my;
mx = ((ltx + rbx) / 2);
my = ((lty + rby) / 2);
if (mx<=ltx && my <=lty){
if (matrix[ltx][lty] == target | matrix[rbx][lty] == target |
matrix[ltx][rby] == target | matrix[rbx][rby] == target){
return true;
}
return false;
}
//定义递归步
else{
bool res = false;
if (target > matrix[mx][my]){
res |= searchSmallMatrix(matrix, target, mx, my, rbx, rby);
res |= searchSmallMatrix(matrix, target, ltx, my+1, mx-1, rby);
res |= searchSmallMatrix(matrix, target, mx+1, lty, rbx, my - 1);
}
else if (target < matrix[mx][my]){
res |= searchSmallMatrix(matrix, target, ltx, lty, mx, my);
res |= searchSmallMatrix(matrix, target, ltx, my + 1, mx-1, rby);
res |= searchSmallMatrix(matrix, target, mx+1, lty, rbx, my-1);
}
else{
return true;
}
return res;
}
}
};
四、心得体会
- 对于递归算法,最重要的是能够明确表示递归基及递归步,在递归步中确定可以降低问题规模。
- 同时也应注意特殊情况的检查,例如矩阵坐标越界及规模为0的特殊情况。