python 二分查找_python(七):矩阵的二分查找

摘要:

学习leetcode_240: search-a-2d-matrix-ii的解法:学习矩阵的二分查找(二维)。

正文:

1、问题描述

Write an efficient algorithm that searches for a value in an m x n matrix. This matrix has the following properties:

  • Integers in each row are sorted in ascending from left to right.
  • Integers in each column are sorted in ascending from top to bottom.

Example:

Consider the following matrix:

[
  [1,   4,  7, 11, 15],
  [2,   5,  8, 12, 19],
  [3,   6,  9, 16, 22],
  [10, 13, 14, 17, 24],
  [18, 21, 23, 26, 30]
]

Given target = 5, return true.

Given target = 20, return false.

(**分析**)

思路1:分解为一维的二分查找

由于每一行、每一列都已经是排好序了的,那么可以进行m个length=n的二分查找(或n个length=m的二分查找)。算法复杂度大概是O(nlogn),缺陷很明显,只用到了一个维度的排序信息,浪费了另一个维度的排序信息。

思路2:从左下或右上开始进行线性单步查找

类似于leetcode_11: container-with-most-water、leetcode_167: two-sum-ii-input-array-is-sorted和leetcode_345: reverse-vowels-of-a-string,题目的“信息结构”能够让一些线性单步查找成为可能(排好序、最大最小等)。在leetcode_240中,左下和右上是一个特殊的起点,以左下为例,如果该值大于target,则其右所有的数都会大于target,因此该行就不再需要检查而直接跳到上一行(i-=1);如果该值小于target,则其上所有的数都会小于target,因此该列就不再需要检查而直接跳到下一列(j+=1)。如此反复,充分利用了两个维度的排序信息,能够以O(m+n)来完成查询。

f2d05b7295ba89db1bfe203f0e017e27.png
基本上沿着“对角线”逐步查询

思路3:分治法+二维二分法

从一个矩阵的中间点来看,如果该点大于target,那么其右下方所有的点都会大于target,而剩余部分可以分解为两个子矩阵继续查找;如果该点小于target,那么其左上方所有点都会小于target。如果先在对角线上找到一点(对角线也是一个排好序的数组),满足条件diag[i]<target<diag[i+1],那么可以将整个矩阵分解为两个子矩阵,然后同样地地分解该子矩阵为两个子矩阵继续查找(递归)。分治法的基线条件是输入为空矩阵时,返回False。如此反复,这样也充分利用了两个维度的排序信息。

d55ec0bbee0e9d3c655118448a3c50c4.png
不断地进行二维的二分

2、python代码实现

思路1:

3ae97a38869fd436c8baa1166a785b43.png
每一行进行一次二分查找

思路2:

55c724612b6cd2088e2f7ab8260114cf.png
从左下开始,沿着“对角线”进行查找

思路3:

44b44601b9652eeb487c8d40fa5f0766.png

test:

构建了一个5000X5500的较大矩阵进行查询,查看三个思路的运行时间差异,可以看到,思路2和3的效率确实比思路1要高一个数量级,而思路1肯定也会比暴力搜索快很多。

409998de8dec4dcf9d345aa2f43d01e5.png

a0cb001f55f33b5bf1eec367a99692f1.png

3eadbba0f72c6623b9b292a62ba93193.png

610f5d3fe7e67316e021027f0b695079.png

3、启发

已知的条件和求解目标的形式,很多时候都蕴含了非常有用的信息(以序信息为主),如果能够充分而巧妙地利用,是能够显著增加程序效率的。这不仅会体现在leecode等解题过程中,实际环境里也会常常遇到。这些思路往往是二分、线性、递归等等,需要在学习和工作中多多总结,让代码更有效率。

leetcode_240.py​github.com
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值