2025/7/17
题目(medium):


我的思路:
已经知道行列都是按从小到大的顺序排列好的,而我们知道二分查找很适合用于这种已经排好序的数组中进行查找操作。所以考虑以对角线上的位置为起点,以行列的最右边、最下边为终点,在遍历对角线的过程中,对行列同时进行二分查找的操作

大概是这么个意思
代码如下:
class Solution:
def searchMatrix(self, matrix: List[List[int]], target: int) -> bool:
#考虑行列同时折半查找,以对角线为起点
m,n = len(matrix), len(matrix[0])
for i in range(min(m,n)): #以行列数最小值为遍历可以达到的最大值防止越界
#start代表是当前所在对角线位置
start = i
#更新左右上下的边界位置
up,down = i,m-1
left,right =i,n-1
#行进行折半查找
while left <= right:
mid = (left + right) //2
midNum = matrix[start][mid]
if midNum == target:
return True
elif midNum > target:
right = mid-1
elif midNum < target:
left = mid+1
#列进行折半查找
while up <= down:
mid = (up + down) // 2
midNum = matrix[mid][start]
if midNum == target:
return True
elif midNum > target:
down = mid-1
elif midNum < target:
up = mid + 1
return False #查到末尾了还没查到那就是没有了
时间复杂度:O(min(m,n)*(log2n + log2m) 【感觉好像也不低哇】
空间复杂度:O(1)
优化思路:
造成时间复杂度过大的原因主要是,目标值越接近右下角,那遍历搜索的时间就越接近于逐行都二分查找一遍,尤其是在数组越来越大的时候,就更加没有优势了。
那可不可以考虑,先通过二分查找确定元素大致会处于哪一行,然后再在这行中进行二分查找呢?如果可以这样的话那时间复杂度就可以优化到O(log2m + log2n)
但是实际上要定位到哪一行似乎比较困难,因为从头开始看的话,任意一行开头数字大于target的都有后面可能存在target;那从结尾看的话,任意一行结尾数字小于target的前面都有可能存在target。
所以只能说排除一定不存在target的行,但是还是不能够定位到target具体在哪一行,所以这个思路是没有办法实现的
更好地思路:
那上面优化的时候想到了,从结尾开始比对的话,要是比target小,那肯定可以排除不在这一行。要是比target大,那就前面还有可能存在target。
也就是说,从右上角(0,n-1)的位置开始搜索,如果当前(x,y)位置的值>target,那就y--;如果当前(x,y)位置的值<target,那就x++。这样进行Z字形搜索即可
终止条件就是当(x,y)掉出索引范围的时候,那就说明target不在这里面
代码如下:
class Solution:
def searchMatrix(self, matrix: List[List[int]], target: int) -> bool:
#考虑从右上角开始搜索
m,n = len(matrix),len(matrix[0])
x,y = 0,n-1 #x,y从右上角开始搜索
#有相等,大于,小于三种情况
while(x < m and y >= 0):
curNum = matrix[x][y]
if curNum == target: #相等直接返回
return True
elif curNum > target: #当前值比目标值还大,目标值可能在这行前面
y -= 1
elif curNum < target: #当前值比目标值还小,说明这行不可能存在目标值,所以进入下一行
x += 1
return False
时间复杂度:O(m+n)
空间复杂度:O(1)
太优雅了
总结:
①对排好序的数组中查找,很快就能反应过来是二分查找
②对于这种有很大很多块的有序的矩阵,考虑排除法,优先选择排除一定没有的部分,而不是优先考虑可能有的部分可以更好地优化思路
662

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



