1. 题目
在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
例如,下面的二维数组就是每行、每列都递增排序。如果在这个数组中查找数字7,则返回True;如果查找数字5,由于数组总不含有该数字,则返回False。
1 | 2 | 8 | 9 |
---|---|---|---|
2 | 4 | 9 | 12 |
4 | 7 | 10 | 13 |
6 | 8 | 11 | 15 |
2. 解题思路
当我们需要解决一个复杂的问题时,一个很有效的办法就是从一个具体的问题入手。通过分析简单具体的例子,找出普遍的规律。
2.1 思路1
最笨的方法,使用两层遍历来遍历二维数组中的每一个元素,看是否含有该数字。很明显,这种思路并没有用上条件
每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序
。
若该数组为n行m列,则时间复杂度O(n*m),空间复杂度S(1)。
2.2 思路2
在思路1的基础上,对每一行元素利用二分查找算法来判断目标数字是否在本行之内。
若该数组为n行m列,则时间复杂度O(nlogm),空间复杂度S(1)。
2.3 思路3
充分利用条件
每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序
,在每次判断的时候,用每一行的最小值去比较,那么如果比最大还大或者比最小还小,就直接能排除掉这一行。或者是,用每一列的最大/最小值去比较,那么如果比最大还大或者比最小还小,就直接能排除掉这一列。只能从二维数组的左下或右上角元素开始比较,如果从左上或右下角比较的话,比左上角大的时候既不能排除一行也不能排除一列,比右下角小的情况也是类似。
若该数组为n行m列,则时间复杂度O(n+m),空间复杂度S(1)。
3. 代码实现
3.1 解法一
思路1的代码实现:
class Solution:
def __init__(self):
pass
def find_in_matrix(self, matrix, target):
"""在二维数组中查找是否含有某元素
:param matrix: 二维数组
:param target: 目标元素
"""
for row in matrix:
for element in row:
if element == target:
return True
return False
3.2 解法二
在思路1中每次判断只能排除掉1个值,思路2中的每次判断能排除更多的值,效率也更高。当然这种思路也可以通过递归来实现。
思路2的代码实现:
class Solution:
def __init__(self):
pass
def find_in_matrix(self, matrix, target):
"""在二维数组中查找是否含有某元素
每次判断排除掉一行或是一列元素
:param matrix: 二维数组
:param target: 目标元素
"""
if matrix and len(matrix) > 0 and len(matrix[0]) > 0:
for row in matrix:
left = 0
right = len(row) - 1
while left <= right:
mid = (left + right) // 2
if row[mid] == target:
return True
elif row[mid] > target:
right = mid - 1
else:
left = mid + 1
return False
3.3 解法三
在思路1中每次判断只能排除掉1个值,思路3中的每次判断能排除一行或是一列的值,当然效率更高。
思路3的代码实现:
class Solution:
def __init__(self):
pass
def find_in_matrix(self, matrix, target):
"""在二维数组中查找是否含有某元素
每次判断排除掉一行或是一列元素
:param matrix: 二维数组
:param target: 目标元素
"""
found = False
if matrix and len(matrix) > 0 and len(matrix[0]) > 0:
rows = len(matrix)
columns = len(matrix[0])
row = 0
column = columns - 1
while row < rows and column >=0:
if matrix[row][column] == target:
found = True
break
elif matrix[row][column] > target:
column -= 1
else:
row += 1
return found
4. 总结
结合之间学习的二分查找算法(每次排除当前剩余的一般的元素)和这次的二维数组查找,我发现查找类的算法,都有一个特点:
- 一定会与全部或某些元素进行比较;
- 通过比较排除1个或多个元素;
- 通过每次比较能够排除掉的元素越多,那么这种算法的效率也就越高;
5. 参考文献
[1] 剑指offer丛书
[2] 剑指Offer——名企面试官精讲典型编程题