两次二分查找解决该问题,第一次可能在哪一行,第二次找这一行中是否真的存在 target
。
题目
编写一个高效的算法来判断 m x n 矩阵中,是否存在一个目标值。该矩阵具有如下特性:
- 每行中的整数从左到右按升序排列。
- 每行的第一个整数大于前一行的最后一个整数。
示例
示例 1:
matrix = [ [1 , 3 , 5 , 7 ], [10 , 11 , 16 , 20 ], [23 , 30 , 34 , 50 ] ] target = 3
示例 2:
matrix = [ [1 , 3 , 5 , 7 ], [10 , 11 , 16 , 20 ], [23 , 30 , 34 , 50 ] ] target = 13
考察知识点
二分查找
核心思想
方法一、一次性二分查找
利用矩阵本身的有序性,先逐行遍历,拼接成一个 list
,然后对这个 list
进行二分查找操作。
方法二、查找第一个大于目标值的数
将问题转化为,查找第一个大于目标值的数,进行两次二分查找。
第一次二分查找,确定 target
所在的行。
第二次二分查找,确定这一行中是否有 target
。
方法三、逐行遍历寻找
不进行二分查找,一行一行的遍历过去。
Python版本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 from typing import Listclass Solution : def searchMatrix (self, matrix: List[List[int ]], target: int ) -> bool: all_ints = [] for i in matrix: all_ints += i left = 0 right = len (all_ints) while left < right: mid = left + (right - left) // 2 if all_ints[mid] == target: return True elif all_ints[mid] < target: left = mid + 1 else : right = mid return False Input = [ [ [1 , 3 , 5 , 7 ], [10 , 11 , 16 , 20 ], [23 , 30 , 34 , 50 ] ], [ [1 , 3 , 5 , 7 ], [10 , 11 , 16 , 20 ], [23 , 30 , 34 , 50 ] ] ] Input1 = [3 , 13 ] Answer = [True , False ]if __name__ == "__main__" : solution = Solution() for i in range (len (Input)): print("-" *50 ) result = solution.searchMatrix(Input[i], Input1[i]) if result == Answer[i]: print(True ) else : print(False ) print(Answer[i]) print(Input[i])
时间复杂度 : 由于是标准的二分查找,时间复杂度为 \(O(log(m \times n))\) 。
空间复杂度 : \(O(m\*n)\) 。
执行用时 :36 ms, 在所有 Python3 提交中击败了94.68%的用户
内存消耗 :14.4 MB, 在所有 Python3 提交中击败了100.00%的用户
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 class Solution : def searchMatrix (self, matrix: List[List[int ]], target ): if not len (matrix) or not len (matrix[0 ]): return False left, right = 0 , len (matrix) while left < right: mid = (left + right) // 2 if matrix[mid][0 ] == target: return True if matrix[mid][0 ] <= target: left = mid + 1 else : right = mid select_col = right-1 if right > 0 else right left, right = 0 , len (matrix[select_col]) while left < right: mid = (left + right) // 2 if matrix[select_col][mid] == target: return True if matrix[select_col][mid] < target: left = mid + 1 else : right = mid return False
时间复杂度 : 两次二分查找,时间复杂度为 \(O(log(m) + log(n))\) 也就是 \(O(log(m \times n))\) ,但是这是极少数极端情况,大多数情况下都不会循环这么多次,所以这个方法最好。
空间复杂度 : \(O(1)\) 。 执行用时 :28 ms, 在所有 Python3 提交中击败了99.53% 的用户
内存消耗 :14.5 MB, 在所有 Python3 提交中击败了100.00%的用户
class Solution : def searchMatrix (self, matrix: List[List[int ]], target: int ) -> bool: if not len (matrix) or not len (matrix[0 ]): return False rows, cols = len (matrix), len (matrix[0 ]) if rows > 0 and cols > 0 : row = 0 col = cols - 1 while row < rows and col >= 0 : if matrix[row][col] == target: return True elif matrix[row][col] > target: col -= 1 else : row += 1 return False
时间复杂度 : \(O(m + n)\) 。
空间复杂度 : \(O(1)\) 。 执行用时 :60 ms, 在所有 Python3 提交中击败了71.15%的用户 内存消耗 :14.3 MB, 在所有 Python3 提交中击败了100.00%的用户
参考链接
Grandyang
LeetCode用户评论