剑指offer 第二版(Python3)--二维数组中的查找

第2章 面试需要的基础知识

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

第3章 高质量的代码

第4章 解决面试题的思路

第5章 优化时间和空间效率

第6章 面试中的各项能力

第7章 两个面试案例

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

示例:
输入:
  matrix = [[1, 3, 5, 8],
      [9, 11, 16, 21],
      [10, 15, 35, 55]]
  target = 15
输出: true

解题思路
  最简单的方法是遍历一次二维数组,逐个比较元素,这种方法时间复杂度为O(nm),mn是二维数组行列数乘积。显然这是一种很low的方法,没有利用到排序数组的性质。
  比较元素是无法避免的操作,关键是如何减少比较的次数,这就要充分利用到排序数组的特性。
  从右上角开始查找,利用该二维数组的性质:
    每一行都按照从左到右递增的顺序排序,
    每一列都按照从上到下递增的顺序排序
  即对于右上角的值 m,m 是该行最大的数,是该列最小的数。用某行最大或某列最小与 target 比较,每次可剔除一整行或一整列。
  每次将 m 和目标值 target 比较:
  1. 当 m > target,由于 m 已经是该行最大的元素,想要更小只有从列考虑,取值左移一位;
  2. 当 m < target,由于 m 已经是该列最大的元素,想要更大只有从行考虑,取值下移一位;
  3. 当 m = target,找到该值,返回 true。

  以示例为例,我们尝试从右上角开始比较,发现target>matrix[0][0],由于matrix[0][0]的右边和下边的数都比它大,所以无法排除其余数字,因此一次比较只排除了一个数,这种效率是最低的。我们换个角度,现在我们尝试从右上角开始比较, 发现target>matrix[0][3],再根据题目给出的排序数组性质,可知matrix[0][3]左边的数都比target小,无需再和此行中右边的数比较,这里便利用了排序数组的性质减少了比较次数,然后跳到下一行继续比较,发现target<matrix[1][3],由于无法排除左边所有数,因此向左逐个比较,直到遇到matrix[1][1]<target,可知matrix[1][1]左边的数都比target小,于是调到下一行继续比较,发现matrix[2][1]==target,找到目标数,返回true。

  我们不能选择左上角或者右下角的数字开始比较,因为我们不可能一次排除所在行或者所在列,这样就无法快速的缩小查找范围

实战
牛客网 二维数组中的查找

class Solution:
    # array 二维列表
    def Find(self, target, array):
        # write code here
        if not array or not array[0] or target is None:
            return False
        if array[0][0] > target or array[-1][-1] < target:
            return False
        rows, cols = len(array), len(array[0])
        r, c = 0, cols - 1
        while r < rows and c >= 0:
            if array[r][c] == target:
                return True
            if array[r][c] < target:
                r += 1
            else:
                c -= 1
        return array[r][c] == target

类似题目:
LeetCode 74 搜索二维矩阵
  注意此题和上题稍有不同,所以解法可以更快
  LeetCode中最佳解法,最大化的利用了排序数组性质。刷题时遇到排序数组,要首先想到二分法。第一个while循环对行数进行二分查找,找到target所在行,第二个while循环是对上一步找到的行进行二分查找。

class Solution:
    def searchMatrix(self, array: List[List[int]], target: int) -> bool:
        if not array or not array[0] or target is None:
            return False
        if array[0][0] > target or array[-1][-1] < target:
            return False
        rows, cols = len(array), len(array[0])
        up, down = 0, rows-1
        r, c = 0, 0
        while up <= down:
            mid = (up + down) >> 1
            if array[mid][0] > target:
                down = mid - 1
            elif array[mid][-1] < target:
                up = mid + 1
            else:
                r = mid
                break
        left, right = 0, cols-1
        while left <= right:
            mid = (left + right) >> 1
            if array[r][mid] > target:
                right = mid - 1
            elif array[r][mid] < target:
                left = mid + 1
            else:
                c = mid
                break
        return array[r][c] == target
参与评论 您还未登录,请先 登录 后发表或查看评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:编程工作室 设计师:CSDN官方博客 返回首页

打赏作者

qq_27668313

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值