一、环境说明
- 本文是 leetcode 74题 :搜索二维矩阵,使用c语言实现
- 使用二分搜索实现。
- 测试环境:Visual Studio 2019
二、代码展示
bool searchMatrix(int** matrix, int matrixSize, int* matrixColSize, int target) {
int left = 0, right = matrixSize * matrixColSize[0] - 1, mid = 0, row = 0, column = 0;
while (left <= right) {
mid = left + ((right - left) >> 1);
row=(mid+1)%matrixColSize[0]==0?(mid+1)/matrixColSize[0]-1:(mid+1)/matrixColSize[0];
column = mid % matrixColSize[0];
if (matrix[row][column] >= target) {
right = mid - 1;
}
else {
left = mid + 1;
}
}
row=(left+1)%matrixColSize[0]==0?(left+1)/matrixColSize[0]-1:(left+1)/matrixColSize[0];
column = left % matrixColSize[0];
if (row >= matrixSize || column >= matrixColSize[0]) {
return false;
}
if (target == matrix[row][column]) {
return true;
}
return false;
}
三、思路分析
- 代码思路见注释
- 这是一个从左到右,从上一行到下一行严格升序的二维矩阵,可以把前一行和后一行拼接起来,拼接所有行,就是一个一维有序数组,通过二分搜索,我们可以得到target在数组里的下标。我们脑子里有这个一维数组就可以了,实际上,直接操作二维矩阵可以减少时空复杂度。可以用一些小学奥数知识,将数组下标转换成矩阵的行号和列号。具体操作看代码注释。
- 需要注意的是,我们搜索到的left是最终的数组下标,在判断它对应的元素和target是否相同前,需要判断left是否超出矩阵范围。这是因为二分搜索的边界问题,比如对于1*1矩阵,当target大于矩阵中那一个元素,二分搜索的left最终是1,但矩阵的边界是0行0列,此时就造成了越界。需要提前判断,left越界,答案肯定是错误的,而且也不能去越界访问内存,编译器会抛出异常,OJ平台报heap-buffer-overflow。
- 这道题还有一个奇妙的思路,因为矩阵按列也是递增的,那么可以对第一列进行二分查找,找到最后一个小于等于target的行号,在这一行里,一定包括target这个元素,因为下一行的首元素就大于target,或者下一行不存在了,找到这一行,再进行一次二分查找,如果找到target,返回true,找不到,返回false即可。时空复杂度和本题解法一样,但是思路很有意思,读者可以自行实现。
四、AC
![AC](https://i-blog.csdnimg.cn/blog_migrate/4a556bb849f9edd0da5c71a20645a548.png)
五、复杂度分析
- 时间复杂度:O(lognm),n是矩阵的行数,m是矩阵的列数。
- 空间复杂度:O(1),除了若干变量使用的常量空间,没有使用线性空间。