面试题3:二维数组中的查找

二维数组的查找

需要注意的是看清楚题目,如果该矩阵的某行的最后一个小于其下一行的第一个,那么下面的做法是合适的,但是如果是该矩阵的某行的最后一个数值和下一行的第一个没有任何关系,那么下面的做法则是不合适的。前者标记为题型1,后者标记为题型2

题型1

做法1

从第一行的最后一列开始搜索(从其他方向应该也可以,但是要控制好边界),如果小于目标值则向下移动一行,如果大于目标值则向左移动一列。

class Solution(object):
    def searchMatrix(self, matrix, target):
        """
        :type matrix: List[List[int]]
        :type target: int
        :rtype: bool
        """
        row = len(matrix)
        if row == 0:
            return False
        col = len(matrix[0])
        if col == 0:
            return False
        h_row = 0
        h_col = col-1
        if target < matrix[0][0]:
            return False
        elif target > matrix[row-1][col-1]:
            return False
        while h_row < row and h_col >= 0:                
            if matrix[h_row][h_col] > target:
                h_col -= 1
            elif matrix[h_row][h_col] < target:
                h_row += 1
            else:
                return True
        return False

缺点:如果其在最后一行,试想一下,如果目标值在左下角的话,则那么它将会移动行数目加上列数目,即M+N,能不能做到只有M或者N呢?看下面的做法。

做法2

思路很简单,先找到其所在的行,再去找所在的列,那么其时间复杂度就变成了行数目和列数目的较大值。

class Solution(object):
    def searchMatrix(self, matrix, target):
        """
        :type matrix: List[List[int]]
        :type target: int
        :rtype: bool
        """
        if not matrix or not len(matrix[0]):
            return False
        top = 0
        bottom = len(matrix) - 1
        row = -1
        while top <= bottom:
            mid = top + ((bottom - top) >> 1)
            if matrix[mid][0] <= target <= matrix[mid][-1]:
                row = mid
                break
            elif target < matrix[mid][0]:
                bottom = mid - 1
            else:
                top = mid + 1
        if row == -1:
            return False
        left = 0
        right = len(matrix[row]) - 1
        while left <= right:
            mid = left + ((right - left) >> 1)
            if matrix[row][mid] == target:
                return True
            elif matrix[row][mid] < target:
                left = mid + 1
            else:
                right =  right - 1
        return False

做法3

还有不得不提到的二分查找算法,注意这里的二分查找不能直接用在二维数组上,而是需要转化成一维数组的思维,使得每个数字都有机会被访问到,避免出现一会向上移动一会向下移动的死循环。其时间复杂度为log2(M+N),个人觉得当M和N都很大的时候,这种方法会快于做法2,相反的情况用做法2可能会更快一些。

class Solution(object):
    def searchMatrix(self, matrix, target):
        """
        :type matrix: List[List[int]]
        :type target: int
        :rtype: bool
        """
        m = len(matrix) 
        if m == 0:
            return False 
        n = len(matrix[0]) 
        if n == 0: 
            return False 
        left = 0 
        right = m * n - 1 
        while left <= right: 
            mid = left + (right - left) / 2 
            i = mid / n 
            j = mid % n 
            if target < matrix[i][j]: 
                right = mid - 1 
            elif target > matrix[i][j]: 
                left = mid + 1 
            else: 
                return True 
        return False 

做法4

序列的语法糖-in

class Solution(object):
    def searchMatrix(self, matrix, target):
        """
        :type matrix: List[List[int]]
        :type target: int
        :rtype: bool
        """
        for i in matrix:
            if target in i:
                return True
        return False

非常的简单明了,但是它的时间复杂度相对较高,所以我们可以再优化一下,不是每一行都进行比较,而是先找到相应的行,再判断是否存在。

class Solution(object):
    def searchMatrix(self, matrix, target):
        if not matrix or not matrix[0]: return False
        for row in matrix:
            if target==row[-1]: return True
            elif target<row[-1]:
                return target in row
        return False

题型2

原理为:从矩阵的右上角开始比较,如果小于目标值,说明目标值比该行的最大值还要大,所以去除掉该行;如果大于目标值,说明目标值比该列的最小值还要小,所以去除掉该列,直到左下角为止。这道题也可以从左下角开始,到达右上角,总之要满足于该值是一行的最大值,一列的最小值或者一行的最小值,一列的最大值,这样才能去除掉其中的某一个,否则如果从左上角开始,是无法判断去除掉一行还是一列的。

class Solution(object):
    def searchMatrix(self, matrix, target):
        row = len(matrix)
        if not row:
            return False
        col = len(matrix[0])
        if not col:
            return False
        i = 0
        j = col - 1
        while i < row and j >= 0:
            if matrix[i][j] == target:
                return True
            elif matrix[i][j] < target:
                i += 1
            else:
                j -= 1
        return False

题外篇

我们都知道浮点数无法使用==来判断,这是因为无论什么,系统都会将浮点数转化成二进制的表现形式,那浮点数特别是小数,其取每位数乘以2以后的整数部分,那么就会存在0.1的二进制为:

0.1 * 2 = 0.2 整数部分取 00.2 * 2 = 0.4 整数部分取 00.4 * 2 = 0.8 整数部分取 00.8 * 2 = 1.6 整数部分取 10.6 * 2 = 1.2 整数部分取 10.2 * 2 = 0.4 整数部分取 0....

显然这会不断的循环下去,其它的浮点数都是一样的道理,这也导致了0.1+0.2 != 0.3的情况,因为其二进制相加的时候并不相等。

通常的做法是将两个数的差的绝对值去和一个较小的数进行比较,但是这是在没有方法的情况下而使用的,但是Python中提供相应的方法,分别有math.isclose和Decimal,用法如下:

print(0.1+0.2 == 0.3)  # False
import decimal
print(decimal.Decimal('0.1') + decimal.Decimal('0.2') == decimal.Decimal('0.3'))  # True
import math
print(math.isclose(0.1+0.2, 0.3))  # True
posted @ 2017-08-07 16:12  banananana  阅读(254)  评论(0编辑  收藏  举报