剑指Offer_第1题_二维数组中的查找_Python3.6实现

版权声明:转载请联系作者 https://blog.csdn.net/sinat_21591675/article/details/84552627

一、题目描述

在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。
请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。

时间限制:1秒 空间限制:32768K 热度指数:851208 本题知识点: 查找

二、思路:

由于这里的每个一维数组的长度相同,所以这个二维数组相当于一个矩阵(每行的长度相同)。长度不同的情况则另当别论。

思路一:曼哈顿搜索(这是我自己编的一个词^^)

  • 对于这样一个按照 x 和 y 方向递增排列的数组,第一个元素(左上角)一定是最小的,最后一个元素(右下角)一定是最大的。

  • 由于数组元素是分别按行按列递增的,故可以: 记给定的整数为target,数组元素为array[i][j] 。

  • 讨论四个顶点的方向性:

  • 左上角和右下角都是一个迷失点,无论向右(左)和向下(上)都是递增,那么对于一个点,对于向右和向下会产生一个岔路,因此不能起到把复杂问题简单化的降维搜索功能

  • 左下角和右上角是两个很好的分支点

  • 以左下角的元素为原点,往上是递减的方向,往右是递增的方向;
    因此,判断规则就是,如果target比当前值小,上移1位,如果比当前值大,右移1位;
    终止条件是匹配了target,或者行数 /列数超出范围。

  • 同理,右上角也是一个很好的出发点,往下递增,往左递减。

时间复杂度:
在最坏的情况下,这种方法相当于从二维数组的右上角走到了左下角(或沿相反方向),即相当于方形街区的曼哈顿距离,因此时间复杂度为 O ( m + n ) O(m+n) ,其中 m m n n 分别为数组的行数和列数。

思路二:
把每一行看成有序递增的数组,利用二分查找,通过遍历每一行得到答案,时间复杂度是 O ( m l o g n ) O(mlogn) ,其中 m m n n 分别为数组的行数和列数。二分查找的时间复杂度为 O ( l o g n ) O(logn)

只有在 m < < n m << n 的情况下,这种方法才会比思路1快。

思路三:
暴力查找,两层循环,时间复杂度为 O ( m n ) O(mn) ,最慢但一定可以找到。

三、代码

思路一:

  1. 从左下角开始遍历,往右递增,往上递减;如果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

  1. 从右上角开始遍历,往下递增,往左递减;因此,如果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])

猜你喜欢

转载自blog.csdn.net/sinat_21591675/article/details/84552627
今日推荐