题目:
编写一个高效的算法来搜索 m x n 矩阵 matrix 中的一个目标值 target 。该矩阵具有以下特性:
- 每行的元素从左到右升序排列。
- 每列的元素从上到下升序排列。
提示:
- m == matrix.length
- n == matrix[i].length
- 每行的所有元素从左到右升序排列
- 每列的所有元素从上到下升序排列
预备知识:
1.const修饰符,将数据修饰为常类型,不可更改,作用类似于#define
//1.定义常量
congst int i=5;//i为常量
//2.指针使用CONST
char* const pContent;//(1)指针本身是常量不可变
const char *pContent;//(2)指针所指向的内容是常量不可变
const char* const pContent; //(3)两者都不可变
//3.const修饰函数参数
void function(const int Var);//a.传递过来的参数在函数内不可以改变(无意义,因为Var本身就是形参)
void function(const char* Var);//b.参数指针所指内容为常量不可变
void function(char* const Var);//c.参数指针本身为常量不可变(也无意义,因为char* Var也是形参)
//d.参数为引用,为了增加效率同时防止修改。修饰引用参数时:
void function(const Class& Var); //引用参数在函数内不可以改变
void function(const TYPE& Var); //引用参数在函数内为常量不可变
2.auto声明自动变量
auto可以在声明变量的时候根据变量初始值的类型自动为此变量选择匹配的类型,类似的关键字还有decltype
int a = 10;
auto au_a = a;//自动类型推断,au_a为int类型
auto 变量必须在定义时初始化,这类似于const关键字。
定义在一个auto序列的变量必须始终推导成同一类型。例如
auto a4 = 10, a5 = 20, a6 = 30;//正确
auto b4 = 10, b5 = 20.0, b6 = 'a';//错误,没有推导为同一类型
想要拷贝元素:for(auto x:range)
想要修改元素 : for(auto &&x:range)
想要只读元素:for(const auto& x:range)
思路及算法 :
该题可以直接笨办法,将矩阵的每个元素从第一个开始直接遍历到找到匹配数字输出true,或者遍历完输出false,但题目强调了一点——高效,即我们要利用该矩阵的性质用最快的速度完成任务
让我们先创建一个矩阵,这里先创建一维数组,再把一维数组塞到二维数组里
void matrixCreat(vector<vector<int> > &matrix,int m,int n) // 二维数组的建立
{
cout<<"请输入矩阵元素,以空格间隔"<<endl;
vector<int>v;//定义一维数组
int temp=0;
for (int i = 0; i < m; i++)//输入m*n的二维数组
{
v.clear();//子数组返回时要清除
for (int j = 0; j < n; j++)
{
cin >> temp;
v.push_back(temp);
}
matrix.push_back(v);
}
}
然后就开始查找
1.暴力遍历
class Solution {
public:
bool searchMatrix(vector<vector<int>>& matrix, int target)
{
int m = matrix.size(), n = matrix[0].size();
for (int i = 0; i < m; i++)
{
for (int j = 0; j < n; j++)
{
if (matrix[i][j] == target)
{
return true;
}
}
}
return false;
}
};
朴实无华,然而提交代码却显示————超时,所以我们换一种。
2.二分查找
最直接的做法,一行一行的进行二分查找即可。
此外,结合有序的性质,一些情况可以提前结束。
比如某一行的第一个元素大于了 target ,当前行和后边的所有行都不用考虑了,直接返回 false。
某一行的最后一个元素小于了 target ,当前行就不用考虑了,换下一行。
lower_bound( begin,end,num):从数组的begin位置到end-1位置二分查找第一个大于或等于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。
bool searchMatrix(vector<vector<int>>& matrix, int target) {
for (const auto& row: matrix)//对矩阵的行只读
{
//lower_bound返回一个迭代器,指向第一个值不小于k的元素
auto it = lower_bound(row.begin(), row.end(), target);
if (it != row.end() && *it == target)
{
return true;
}
}
return false;
}
3.二叉搜索树
根据该矩阵的性质,我们可以发现,从右上角元素看,矩阵元素的排序刚好符合二叉搜索树的性质,从右上角元素开始,若该行元素均小于target,下一行,若该列元素均大于target,向左移
class Solution
{
public:
bool searchMatrix(vector<vector<int>>& matrix, int target)
{
int row = 0;
int col = matrix[0].size()- 1;
if (matrix.size() == 0 || matrix[0].size() == 0) //矩阵元素为0,直接结束
{return false;}
while (row < matrix.size() && col >= 0)
{
//从右上角元素开始
if (target > matrix[row][col])//该行元素均小于target,下一行
row++;
else if (target < matrix[row][col]) //该列元素均大于target,向左移
col--;
else
return true;//直到匹配到该元素
}
return false;
}
};