题目要求
在一个 n * m 的二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个高效的函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
示例:
现有矩阵 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(即找到该数字)。
给定 target = 20,返回 false(即未找到该数字)。
限制:
0 <= n <= 1000
0 <= m <= 1000
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/er-wei-shu-zu-zhong-de-cha-zhao-lcof
下面展示的解法代表了我对题目的处理思路——首先是自己思考的解法(可能是暴力解法),然后综合leetcode部分题解和论坛上的其他回答写出的较优化解法。
一、基础解法——暴力查找
如果该二维数组没有任何特性,暴力解法可能就是最通用的解法。他的做法就是挨个扫描每行(n)每列(m)的每个元素,如果与目标值相等,返回true,如果遍历完所有元素均没有与目标值相等的,则返回false。代码如下:
bool findNumberIn2DArray01(vector<vector<int>>& matrix, int target)
{
if (matrix.size() == 0 || matrix[0].size() == 0)
{
return false;
}
for (int i = 0; i < matrix.size(); i++)
{
for (int j = 0; j < matrix[0].size(); j++)
{
if (matrix[i][j] == target)
{
return true;
}
}
}
return false;
}

时间复杂度O(n*m)。
二、数字规律——线性查找
根据条件“每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序”,可以直到二维数组的横向和竖向都是有序的,根据这一特性能够很快确定一颗以。
代码如下:
bool findNumberIn2DArray02(vector<vector<int>>& matrix, int target)
{
if (matrix.size() == 0 || matrix[0].size() == 0)
{
return false;
}
int n = matrix.size() - 1, m = matrix[0].size() - 1;
int i = 0, j = m;
while (i <= n && j >= 0)
{
if (target == matrix[i][j])
{
return true;
}
else if (target < matrix[i][j])
{
j--;
}
else if (target > matrix[i][j])
{
i++;
}
}
return false;
}

时间复杂度:O(m+n)。
三、完整测试代码
#include <iostream>
#include <vector>
using namespace std;
//方法一:暴力法
bool findNumberIn2DArray01(vector<vector<int>>& matrix, int target)
{
if (matrix.size() == 0 || matrix[0].size() == 0)
{
return false;
}
for (int i = 0; i < matrix.size(); i++)
{
for (int j = 0; j < matrix[0].size(); j++)
{
if (matrix[i][j] == target)
{
return true;
}
}
}
return false;
}
//方法二:线性查找
bool findNumberIn2DArray02(vector<vector<int>>& matrix, int target)
{
if (matrix.size() == 0 || matrix[0].size() == 0)
{
return false;
}
int n = matrix.size() - 1, m = matrix[0].size() - 1;
int i = 0, j = m;
while (i <= n && j >= 0)
{
if (target == matrix[i][j])
{
return true;
}
else if (target < matrix[i][j])
{
j--;
}
else if (target > matrix[i][j])
{
i++;
}
}
return false;
}
int main()
{
/*
测试用例
[
[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。
给定 target = 20,返回 false。
限制:
0 <= n <= 1000
0 <= m <= 1000
*/
vector<vector<int>> vTest = {
{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}
};
int target01 = 5;
int target02 = 20;
//方法一:暴力查找
cout << findNumberIn2DArray01(vTest, target01) << endl;
cout << findNumberIn2DArray01(vTest, target02) << endl;
//方法二:线性查找
cout << findNumberIn2DArray02(vTest,target01) << endl;
cout << findNumberIn2DArray02(vTest, target02) << endl;
system("pause");
return 0;
}
总结
此外,在浏览其他做法时,发现还有使用二分法和递归的方法来解的,但是十分复杂不好理解,并且从算法复杂度的角度来看,并不是十分的优化,这里不列出来,感兴趣的可以去搜索查看。
本文介绍了如何在按特定顺序排列的二维数组中高效查找数字。首先提出暴力查找方法,然后利用数组的排序特性实现线性查找,将时间复杂度降低到O(m+n)。并提供了完整测试代码验证两种方法的正确性。
707

被折叠的 条评论
为什么被折叠?



