题目详情:https://leetcode.com/problems/search-a-2d-matrix-ii/description/
思路:
1、检查第一列的行首元素,从最后一行开始,如果行首元素小于等于target的行停止,假设该位置为row。target不可能在大于row的行中,因为大于row行中的元素都比target大。
2、检查第一行的列首元素,从最后一列开始,如果列首元素小于等于target,那么在该列停止。假设该列为column,target不可能在大于column的中,因为大于column的列的元素值都大于target
经过以上两步,就确定了target的大体范围,接下来就是在该范围内进行详细 查找,从第二行,第二列开始。
举个例子:
[
[1, 4, 7, 11, 15],
[2, 5, 8, 12, 19],
[3, 6, 9, 16, 22],
[10, 13, 14, 17, 24],
[18, 21, 23, 26, 30]
]
在上面的矩阵中,查找9,即target=9。
1、首先从最后一行开始检查行首元素,row=m-1。18>9,row=row-1;10>9,row=row-1;3<=9满足题意。此时row为2。
2、从最后一列开始检查列首元素,column=n-1。15>9,column=column-1;
11>9,column=column-1;7<=9,满足条件,停止循环。此时column为2。
此时就能够确定target大体范围,即行范围(1,2),列范围(1,2)。然后在这个范围进行详细查找就可以了。
# -*- coding:utf-8 -*-
class Solution(object):
def searchMatrix(self, matrix, target):
"""
:type matrix: List[List[int]]
:type target: int
:rtype: bool
"""
if not matrix:
return False
m,n=len(matrix),len(matrix[0])
if n==0:
return False
row=m-1
while row>=0:#检查每一行
if target>=matrix[row][0]:#如果列首元素小于等于target
break#那么停止循环,因为target所在的行只可能小于等于row
row-=1
column=n-1
while column>=0:#检查每一列
if target>=matrix[0][column]:#如果列首元素小于等于target
break#停止循环,target所在的列只可能小于等于column
column-=1
#以上两个循环为找target的大体范围
if matrix[row][0]==target or matrix[0][column]==target:#检查行首和列首元素,因为不检查第一行和第一列
return True
i,j=1,1#行,列从(1,1)开始
#以下为开始循环,行循环的范围为(1,row),列循环的范围为(1,column)
while i<=row:
j=1
while j<=column:
if matrix[i][j]==target:
return True
j+=1
i+=1
return False
但是这种方法的效率太低,我就开始考虑别的方法了。既然一开始就可以缩小范围,那么为什么不可以把范围缩小到只有一个元素呢?由此想到的思路就是循环探测“行首“和“列首“的过程。
举个例子:
[
[1, 4, 7, 11, 15],
[2, 5, 8, 12, 19],
[3, 6, 9, 16, 22],
[10, 13, 14, 17, 24],
[18, 21, 23, 26, 30]
]
在上面的矩阵查找9,即target=9。
第一次循环结束后,row=2,column=2。
第二次循环,去掉第一行和第一列,并且矩阵的行数,列数为2、2,即我们要访问的矩阵为
[
[5,8],
[6,9]
]
然后再依次检查该矩阵的行首元素和列首元素。从最后一行开始检查行首元素,6<=9成立,结束循环,此时的row为1(如果以上面的小矩阵为准的话,大矩阵的row为2);从最后一列开始检查列首元素,8<=9成立,结束循环,此时的column为1(同样以小矩阵为准)。第二次结束,此时row=1,column=1
第三次循环,去掉第一行,第一列,此时我们要访问的矩阵的行数,列数为1、1,即:
[
[9]
]
这样就把范围缩小到只有一个元素了。这是思路,具体的实现会有点差异。
具体代码为:
# -*- coding:utf-8 -*-
class Solution(object):
def searchMatrix(self, matrix, target):
"""
:type matrix: List[List[int]]
:type target: int
:rtype: bool
"""
if not matrix:
return False
m,n=len(matrix),len(matrix[0])
if n==0:
return False
row,column,i=m-1,n-1,0#rowlimit和columnlimit用来存储行,列访问的上限,i存储访问的下界
while i<=column and i<=row:#访问的下限不能超过上限
while row>=i:#探测“行首”元素,并一定是真正的行首元素
if target>=matrix[row][i]:#如果某行的“行首”,大于等于target
break#到这个地方停止
row-=1
while column>=i:#探测”列首”元素,同样的不一定为真正的列首元素
if target>=matrix[i][column]:#如果某一列的列首语速小于等于target
break#到这个地方停止
column-=1
if row<i and column<i:#不存在这个元素
return False
if matrix[row][i]==target or matrix[i][column]==target:#探测'行首'和‘列首’处位置是否等于target,以免漏掉
return True#则返回true
i=i+1#访问下限加1
return matrix[rowlimit][columnlimit]==target
上面这两种方法是自己想到的,两者有相似点。但是这两种方法的效率都不高。当我看到别人写的代码的时候,[吃惊]。厉害啊
代码如下:
# -*- coding:utf-8 -*-
class Solution(object):
def searchMatrix(self, matrix, target):
"""
:type matrix: List[List[int]]
:type target: int
:rtype: bool
"""
if not matrix:
return False
m,n=len(matrix),len(matrix[0])
if n==0:
return False
row,column=0,n-1
while row<m and column>=0:
if matrix[row][column]==target:#等于target则直接返回
return True
elif matrix[row][column]<target:#某一行的最后一个元素,其实也不一定是真正的最后一个元素,小于target
row+=1#那么需要增大matrix[row][column]的值,故将row加1,因为此时的matrix[row][column]已经是最后一个元素了
else:#matrix[row][column]>target,需要减小matrix[row][column]的值
column-=1#将column减1
return False#执行到这,说明没有找到