搜索二维矩阵II(分治法和蛇行)

问题来源力扣算法面试汇总

问题描述:编写一个高效的算法来搜索 m x n 矩阵 matrix 中的一个目标值 target。该矩阵具有以下特性:

  • 每行的元素从左到右升序排列。
  • 每列的元素从上到下升序排列。

例子
输入:
[
[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]
]
输出:
给定 target = 5,返回 true。
给定 target = 20,返回 false。

# 二维矩阵
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]
]
# 寻找目标
# target = 5
target = 20

1. O ( n 2 ) O(n^2) O(n2)算法

思路:本质就是暴力算法,一个一个地查找。

# 矩阵为空的情形
if len(matrix) == 0: return False
# 矩阵非空的情形
# 行列数
n, m = len(matrix), len(matrix[0])
# 两层遍历
for i in range(n):
	for j in range(m):
		if matrix[i][j] == target: 
			return True
return False

2. O ( n l g n ) O(nlgn) O(nlgn)算法

思路:暴力算法忽略了二维矩阵元素有序的信息。利用每一行有序的信息,我们可以关于将二维矩阵分成四个部分,其中target只可能落在两个小矩阵里面,然后再递归对这两个小矩阵查找。

步骤1:当前矩阵下,检验矩阵是否为空,以及target是否大于最大值或者小于最小值,如果任何一个满足,则返回false;如都不满足,则进行步骤2
步骤2:mid=中间列的索引,计算row使得matrix[row-1][mid]<=target<=matrix[row][mid],如果target=matrix[row-1][mid]或者target=matrix[row][mid],则返回true;否则,进行步骤3
步骤3:通过步骤2可知,matrix[row-1][mid]<target<matrix[row][mid]严格成立,我们据此将矩阵划分成四个小矩阵。左上角和右下角矩阵是不可能的,target只可能落在左下角和右上角矩阵内。
步骤4:对左下角和右上角矩阵做递归

        def search_submatrix(matrix, target, left, right, up, down):
            if left > right or up > down:
                return False
            elif target < matrix[up][left] or target > matrix[down][right]:
                return False
            else:
                row = up
                mid = (left + right) // 2
                while row <= down and target >= matrix[row][mid]:
                    if target == matrix[row][mid]:
                        return True
                    row = row + 1
                return search_submatrix(matrix, target, left, mid-1, row, down) or search_submatrix(matrix, target, mid+1, right, up, row-1)

        
        left, right, up, down = 0, len(matrix[0])-1, 0, len(matrix)-1
        return search_submatrix(matrix, target, left, right, up, down)

3. O ( n ) O(n) O(n)算法

根据官方题解,其实有一个更加巧妙的方法。

思路:从左下角位置开始,如果当前元素比target小,则往后移动一位;如果当前元素比target大,则往上移动一位。

# 行索引
cur_i = len(matrix) - 1
# 列索引
cur_j = 0

while True:
    if target == matrix[cur_i][cur_j]:
        print(True)
        break
    elif target > matrix[cur_i][cur_j]:
        cur_j += 1
    else:
        cur_i -= 1
    if cur_i < 0 or cur_j > len(matrix[0]):
        print(False)
        break
  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值