##题目描述
给你一个满足下述两条属性的 m x n
整数矩阵:
- 每行中的整数从左到右按非严格递增顺序排列。
- 每行的第一个整数大于前一行的最后一个整数。
给你一个整数 target
,如果 target
在矩阵中,返回 true
;否则,返回 false
。
例:
nums = [[1,3,5,7],[10,11,16,20],[23,30,34,60]]
##解法一-两次二分
我们为了方便理解将其中的条件循环改成了if-elif-elif来展开,具体的解释会在具体的代码标注中展开
def searchMatrix(matrix,target):
n , m = len(matrix) , len(matrix[0])
left = 0
right = n - 1
#第一步我们要先找到对应的target所在的行然后进行相应的查找
#记每一行的数组组成的列表为[a[0],......,a[n-1]]
#首先要找到 a[i]=<target<a[i+1]
while left < right :
mid = (left + right + 1)//2#我们进行上取整是为了防止陷入死循环
if matrix[mid][0] < target :
left = mid#区间内部的数是严格递增的因此在此不知道mid所在行是否含有target
elif matrix[mid][0] > target :
right = mid - 1
else:
left = mid##关键点等于的时候要把左部边界置于中间边界位置
##目的是只是单纯的把所在行保留下来
row = left##与第一次二分的理解一摸一样,实在不理解就可以自己调试二分关注其落点位置
## 以及左右边界点的收缩
l = 0
r = m - 1
while l < r :
midd = (l + r + 1)//2
if matrix[row][midd] == target :
l = midd
elif matrix[row][midd] > target:
r = mid + 1
else:
l =midd
return matrix[row][l]==target
##解法二-直接一次二分
##分析:
首先我们知道整个矩阵中从左到右且每一行的结尾对应下一行的开始依然严格递增,因此我们可以把整个矩阵压缩成一个一维的递增的数组,因此我们可以直接采用一次二分直接大幅度的减少算法的时间,现在需要关注的一个点便是怎么去把对应的行列下标通过对应的整体的矩阵的m*n来显示,一个方法是相除,一个方法是取余,这样就可以精细到每一行的每一列的具体元素。
def dichotomy(nums,target):
left = 0
n = len(nums[0])
right = len(nums)*len(nums[0]) - 1
while left < right :
mid = (left + right)//2
m = nums[int(mid/n)][mid%n]
if m > target :
right = mid - 1
elif m < target :
left = mid + 1
else:
return True
return False
matrix = [[1,2,3,4],[5,6,7,8],[9,10,11,12]]
print(dichotomy(matrix,3))
##解法四-二叉树(二叉搜索树)
##分析:首先我们知道在这个二维的矩阵中元素之间的变化规律,行中严格单调递增,列中同样也是严格递增,因此我们可以考虑采用搜索二叉树来解决这方面的问题--我们构建左右子树,其中左右子树为新的二叉搜索树,其中右子树的值总是大于其根节点的值,左子树的值总是小于其根节点的值,这一次我们选择的是右上角其实左下角也同样可以操作
##代码示例
def searchMatrix(matrix,target):
if matrix==None or len(matrix)==0:
return False
m = 0
n = len(matrix[0]) - 1
while m < len(matrix) and n >=0 :
if matrix[m][n] == target :
return True
elif matrix[m][n] > target :
n-=1##对应的列数减一
else:
m+=1##对应的行数加一
return False
matrix = [[1,2,3,4],[5,6,7,8],[9,10,11,12]]
print(searchMatrix(matrix=matrix,target=3))