一、题目描述
在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。
请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。时间限制:1秒 空间限制:32768K 热度指数:851208 本题知识点: 查找
二、思路:
由于这里的每个一维数组的长度相同,所以这个二维数组相当于一个矩阵(每行的长度相同)。长度不同的情况则另当别论。
思路一:曼哈顿搜索(这是我自己编的一个词^^)
-
对于这样一个按照 x 和 y 方向递增排列的数组,第一个元素(左上角)一定是最小的,最后一个元素(右下角)一定是最大的。
-
由于数组元素是分别按行按列递增的,故可以: 记给定的整数为target,数组元素为array[i][j] 。
-
讨论四个顶点的方向性:
-
左上角和右下角都是一个迷失点,无论向右(左)和向下(上)都是递增,那么对于一个点,对于向右和向下会产生一个岔路,因此不能起到把复杂问题简单化的降维搜索功能
-
左下角和右上角是两个很好的分支点
-
以左下角的元素为原点,往上是递减的方向,往右是递增的方向;
因此,判断规则就是,如果target比当前值小,上移1位,如果比当前值大,右移1位;
终止条件是匹配了target,或者行数 /列数超出范围。 -
同理,右上角也是一个很好的出发点,往下递增,往左递减。
时间复杂度:
在最坏的情况下,这种方法相当于从二维数组的右上角走到了左下角(或沿相反方向),即相当于方形街区的曼哈顿距离,因此时间复杂度为
O
(
m
+
n
)
O(m+n)
O(m+n),其中
m
m
m 和
n
n
n 分别为数组的行数和列数。
思路二:
把每一行看成有序递增的数组,利用二分查找,通过遍历每一行得到答案,时间复杂度是
O
(
m
l
o
g
n
)
O(mlogn)
O(mlogn),其中
m
m
m 和
n
n
n 分别为数组的行数和列数。二分查找的时间复杂度为
O
(
l
o
g
n
)
O(logn)
O(logn)。
只有在 m < < n m << n m<<n的情况下,这种方法才会比思路1快。
思路三:
暴力查找,两层循环,时间复杂度为
O
(
m
n
)
O(mn)
O(mn),最慢但一定可以找到。
三、代码
思路一:
- 从左下角开始遍历,往右递增,往上递减;如果target比当前值小,上移1位,如果比当前值大,右移1位;终止条件是匹配了target,或者行数/列数超出范围。
# -*- coding:utf-8 -*-
# Python 3.6
class Solution:
# array 二维列表,target 待查找的整数
def Find(self, target, array):
# write code here
m,n = len(array), len(array[0]) # number of rows and columns
# 边界检测
if m <=0 or n <= 0:
return False
# Python的逻辑运算用 or,and,not
if (target < array[0][0]) or (target > array[-1][-1]):
# print('Can not find %s in this array'%target)
return False
# 每行第一个:a[i][0]; 每行最后一个:a[i][-1];每列第一个:a[0][j];每列最后一个:a[-1][j]
# 左上角是最小的,右下角是最大的;每行(列)第一个是这一行(列)的最小值,每行(列)最后一个是这一行(列)的最大值
# 记给定的整数为target,数组元素为array[i][j]
# 以左下角的元素为原点,往上是递减的方向,往右是递增的方向;
# 因此,判断规则就是,如果target比当前值小,上移1位,如果比当前值大,右移1位
# 终止条件是匹配了target,或者行数/列数超出范围
i = m - 1
j = 0
# 这里的循环次数不确定,而且是条件循环,所以用while
while (i >= 0) and (j <= n - 1):
if target == array[i][j]:
return True
elif target < array[i][j]:
i = i - 1
else:
j = j + 1
return False
- 从右上角开始遍历,往下递增,往左递减;因此,如果target比当前值小,左移1位,如果比当前值大,下移1位。
# -*- coding:utf-8 -*-
# Python 3.6
class Solution:
# array 二维列表
def Find(self, target, array):
# write code here
m,n = len(array), len(array[0]) # number of rows and columns
if m <=0 or n <= 0:
return False
# Python的逻辑运算用 or,and,not
if (target < array[0][0]) or (target > array[-1][-1]):
return False
# 从右上角开始遍历
i = 0
j = n - 1
while (i <= m - 1) and (j >= 0):
if target == array[i][j]:
return True
elif target < array[i][j]:
j = j - 1
else:
i = i + 1
return False
实际上python当中没有数组的概念, 而是列表(List), 二维列表相当于二维数组 。
# 获取ndarray的shape的方法
import numpy as np
array = np.array([[1,2,3],[4,5,6]])
m,n = array.shape
print(m,n)
print(array[0][1])
# 获取list的shape的方法
t = [[1,2,3],[4,5,6]]
m,n = len(t), len(t[0])
print(m,n)
print(t[0][1])
print(t[-1][-1])
# 输出每行第一个和最后一个
for i in range(m):
print(t[i][0], t[i][-1])
# 输出每列第一个和最后一个
for j in range(n):
print(t[0][j], t[-1][j])