各位题友大家好! 今天是 @负雪明烛 坚持日更的第 65 天。今天力扣上的每日一题是「74. 搜索二维矩阵」。
解题思路
今天题目重点:每行数字都是升序的;每行的所有数字都比它上面的那一行大。
下面给了多种方法,效率越来越快。
方法一:遍历
该方法就是遍历查找每个位置,看 target 是否出现。这个方法也能通过本题。
class Solution(object):def searchMatrix(self, matrix, target):M, N = len(matrix), len(matrix[0])for i in range(M):for j in range(N):if matrix[i][j] == target:return Truereturn False
class Solution(object):def searchMatrix(self, matrix, target):return any(target in row for row in matrix)
class Solution {public:bool searchMatrix(vector<vector<int>>& matrix, int target) {if (matrix.size() == 0 || matrix[0].size() == 0) return false;const int M = matrix.size(), N = matrix[0].size();int i = 0;while (i < M * N) {if (matrix[i / N][i % N] == target)return true;++i;}return false;}};
- 时间复杂度: $O(M * N)$
- 空间复杂度:$O(1)$
方法二:从左下角或者右上角开始查找
今天这个题目是 240. 搜索二维矩阵 II 的一个特例。建议也把 240 题做一下。
这个方法是利用了矩阵的性质,如果我们从右上角开始遍历:
- 如果要搜索的 target 比当前元素大,那么让行增加;
- 如果要搜索的 target 比当前元素小,那么让列增加;
class Solution(object):def searchMatrix(self, matrix, target):if not matrix or not matrix[0]:return Falserows = len(matrix)cols = len(matrix[0])row, col = 0, cols - 1while True:if row < rows and col >= 0:if matrix[row][col] == target:return Trueelif matrix[row][col] < target:row += 1else:col -= 1else:return False
- 时间复杂度:$O(M + N)$
- 空间复杂度:$O(1)$
方法三:先寻找到所在行
该方法利用了题目给出的矩阵的性质:每行元素都是单调递增的,并且下一行的元素会比本行更大。所以:
如果 target 大于这一行的末尾元素,那么target 一定不在这一行中,只能出现在矩阵的下面的行中。
那么,假如 target < matrix[i][N - 1] 时,说明 target 可能在本行中出现,而且由于下面各行的元素都大于 matrix[i][N - 1] ,所以,不可能在下面的行中出现。此时,可以在本行中使用顺序查找,或者二分查找。
class Solution(object):def searchMatrix(self, matrix, target):M, N = len(matrix), len(matrix[0])for i in range(M):if target > matrix[i][N - 1]:continueif target in matrix[i]:return Truereturn False
class Solution {public:bool searchMatrix(vector<vector<int>>& matrix, int target) {if (matrix.size() == 0 || matrix[0].size() == 0) return false;const int M = matrix.size(), N = matrix[0].size();for (int i = 0; i < M; ++i) {if (target > matrix[i][N - 1])continue;auto it = find(matrix[i].begin(), matrix[i].end(), target);return it != matrix[i].end();}return false;}};
class Solution(object):def searchMatrix(self, matrix, target):M, N = len(matrix), len(matrix[0])for i in range(M):if target > matrix[i][N - 1]:continueindex = bisect.bisect_left(matrix[i], target)if matrix[i][index] == target:return Truereturn False
- 时间复杂度: 在行中遍历查找的时间复杂度是: $O(M + N)$;在行中进行二分查找的时间复杂度是 $O(M + log(N))$
- 空间复杂度:$O(1)$
方法四:两次二分查找
这个方法可以说是方法三的改进。在方法三种,我们是先遍历找到 target 在哪一行,然后在该行遍历或者二分查找的 target 。其实也可以先用二分找到 target 所在的行,然后在该行二分找到 target。
具体做法是,先找到 matrix[i][0] 小于 target 并且 matrix[i + 1][0] > target 的第 i 行,然后在该行内进行二分找到 target。
代码如下:
class Solution(object):def searchMatrix(self, matrix, target):M, N = len(matrix), len(matrix[0])col0 = [row[0] for row in matrix]target_row = bisect.bisect_right(col0, target) - 1if target_row < 0:return Falsetarget_col = bisect.bisect_left(matrix[target_row], target)if target_col >= N:return Falseif matrix[target_row][target_col] == target:return Truereturn False
- 时间复杂度: $O(log(M) + log(N))$
- 空间复杂度:$O(1)$
方法五:全局二分
这个方法,是我们在二维矩阵上进行二分查找,这其实相当于把二维矩阵当做一维来做,要求每一行的最后一个元素小于下一行的第一个元素。
根据 mid 求出在二维矩阵中的具体位置,然后判断 left 和 right 的移动方式。整体做法和一维数组的二分没有区别。
class Solution(object):def searchMatrix(self, matrix, target):M, N = len(matrix), len(matrix[0])left, right = 0, M * N - 1while left <= right:mid = left + (right - left) // 2cur = matrix[mid // N][mid % N]if cur == target:return Trueelif cur < target:left = mid + 1else:right = mid - 1return False
如果用python刷题,在leetcode中是支持使用 numpy 的,可以把 matrix成一维有序的数组,然后按照一维数组去操作查找。
import numpy as npclass Solution(object):def searchMatrix(self, matrix, target):matrix = np.reshape(matrix, [1, -1])return target in matrix
import numpy as npclass Solution(object):def searchMatrix(self, matrix, target):matrix = np.reshape(matrix, [1, -1]).tolist()[0]index = bisect.bisect_left(matrix, target)if index < 0 or index >= len(matrix):return Falsereturn matrix[index] == target
- 时间复杂度: $O(MN + log(MN))$
- 空间复杂度:$O(M*N)$
刷题心得
- 今天提供了很多解法,希望能帮助你打开思路。
- 做完本题之后,去做一下 240. 搜索二维矩阵 II。
OK,以上就是 @负雪明烛 写的今天题解的全部内容了,如果你觉得有帮助的话,求赞、求关注、求收藏。如果有疑问的话,请在下面评论,我会及时解答。
关注我,你将不会错过我的精彩动画题解、面试题分享、组队刷题活动,进入主页 @负雪明烛 右侧有刷题组织,从此刷题不再孤单。
祝大家牛年大吉!AC 多多,Offer 多多!我们明天再见!
