数组/列表 74. 搜索二维矩阵 240. 搜索二维矩阵II

74. 搜索二维矩阵

  • 编写一个高效的算法来判断 m x n 矩阵中,是否存在一个目标值。该矩阵具有如下特性:
    每行中的整数从左到右按升序排列。
    每行的第一个整数大于前一行的最后一个整数。

示例:

示例 1:
输入:
matrix = [
  [1,   3,  5,  7],
  [10, 11, 16, 20],
  [23, 30, 34, 50]
]
target = 3
输出: true

示例 2:
输入:
matrix = [
  [1,   3,  5,  7],
  [10, 11, 16, 20],
  [23, 30, 34, 50]
]
target = 13
输出: false

思路1:

取每行数组的第一个元素与target判断,若target大于当前行第一个元素,且小于下一行第一个元素,则在此行进行匹配。

代码实现1:

class Solution:
    def searchMatrix(self, matrix: List[List[int]], target: int) -> bool:
    	# 特殊情况判断:1、矩阵为空 2、矩阵第一个元素为空 3、目标值为空 都返回False
	    if not (matrix and matrix[0] and len(str(target))):
	        return False
	
	    for i in range(len(matrix)):
	        # 定义一个标志,当目标值匹配到了某一行时,设为1,便于当目标值在此行未匹配到值时,函数直接结束
	        flag = 0
	        # 判断矩阵是否只有一行,防止越界
	        if i + 1 < len(matrix):
	            # 如果目标值匹配到某一行,将flag设为1,并在此行寻找相等的元素
	            if matrix[i][0] <= target < matrix[i + 1][0]:
	                flag = 1
	                for j in matrix[i]:
	                    if j == target:
	                        return True
	            if flag:
	                return False
	        else:
	            for j in matrix[i]:
	                flag = 1
	                if j == target:
	                    return True
	            if flag:
	                return False

思路2:二分查找

注意到输入的 m x n 矩阵可以视为长度为 m x n 的有序数组。
在这里插入图片描述
数组的序号可以由下式方便地转化为原矩阵中的行和列
row = idx // n , col = idx % n。

标准二分查找算法 :
初始化左右序号
left = 0 和 right = m x n - 1。
While left < right :
选取虚数组最中间的序号作为中间序号: mid = (left + right) // 2。
该序号对应于原矩阵中的 row = mid // n行 col = mid % n 列, 由此可以拿到中间元素 elem。该元素将数组分为两部分。
比较 elem 与 target 以确定在哪一部分进行进一步查找。

代码实现2:

class Solution:
    def searchMatrix(self, matrix: List[List[int]], target: int) -> bool:
        # 特殊情况判断
        if len(matrix) == 0:
            return False
        
        m, n = len(matrix), len(matrix[0])
        left, right = 0, m * n - 1
        while left <= right:
            mid = (left + right) // 2
            elem = matrix[mid // n][mid % n]
            if target == elem:
                return True
            else:
                if target <= elem:
                    right = mid - 1
                else:
                    left = mid + 1
        return False

240. 搜索二维矩阵II

  • 编写一个高效的算法来搜索 m x n 矩阵 matrix 中的一个目标值 target。该矩阵具有以下特性:
    每行的元素从左到右升序排列。
    每列的元素从上到下升序排列。

示例:

现有矩阵 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,返回 true。
给定 target = 20,返回 false。

思路1:二分法

首先,我们确保矩阵不为空。那么,如果我们迭代矩阵对角线,从当前元素对列和行搜索,我们可以保持从当前 (row,col)(row,col) 对开始的行和列为已排序。 因此,我们总是可以二分搜索这些行和列切片。我们以如下逻辑的方式进行 : 在对角线上迭代,二分搜索行和列,直到对角线的迭代元素用完为止(意味着我们可以返回 false )或者找到目标(意味着我们可以返回 true )。binary search 函数的工作原理和普通的二分搜索一样,但需要同时搜索二维数组的行和列。

代码实现1:

def binary_search(matrix, target, start, vertical):
    lo = start
    hi = len(matrix[0]) - 1 if vertical else len(matrix) - 1
    while hi >= lo:
        mid = (lo + hi) // 2
        if vertical:  # searching a column
            if matrix[start][mid] < target:
                lo = mid + 1
            elif matrix[start][mid] > target:
                hi = mid - 1
            else:
                return True
        else:  # searching a row
            if matrix[mid][start] < target:
                lo = mid + 1
            elif matrix[mid][start] > target:
                hi = mid - 1
            else:
                return True
    return False


def searchMatrix(matrix, target):
    # an empty matrix obviously does not contain `target`
    if not matrix:
        return False
    # iterate over matrix diagonals starting in bottom left.
    for i in range(min(len(matrix), len(matrix[0]))):
        vertical_found = binary_search(matrix, target, i, True)
        horizontal_found = binary_search(matrix, target, i, False)
        if vertical_found or horizontal_found:
            return True
    return False

思路2:双指针(推荐)

矩阵有四个角,从角落出发:

  • 选左上角,往右走和往下走都增大,不能选
  • 选右下角,往上走和往左走都减小,不能选
  • 选左下角,往右走增大,往上走减小,可选
  • 选右上角,往下走增大,往左走减小,可选

如选左下角:

  1. 首先,我们初始化一个指向矩阵左下角的 [len(matrix) - 1][0] 指针。判断当前指针与目标值的大小关系,直到找到目标并返回True或者指针指向矩阵维度之外返回False。
  2. 根据行是从左到右排序的,列是从上到下排序的,我们执行以下操作:如果当前指向的值大于目标值,则可以 “向上” 移动一行。 否则,如果当前指向的值小于目标值,则可以“向右”移动一列。

代码实现2:

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

思路3:分治算法

我们可以将已排序的二维矩阵划分为四个子矩阵,其中两个可能包含目标,其中两个肯定不包含。

代码实现3:

class Solution:
def searchMatrix(matrix, target):
    if not matrix:
        return False

    def search_rec(left, up, right, down):
        # 指针越界或值越界
        if left > right or up > down:
            return False
        elif target < matrix[up][left] or target > matrix[down][right]:
            return False

        mid = (right + left) // 2

        # Locate `row` such that matrix[row-1][mid] < target < matrix[row][mid]
        row = up
        while row <= down and matrix[row][mid] <= target:
            if matrix[row][mid] == target:
                return True
            row += 1

        return search_rec(left, row, mid - 1, down) or search_rec(mid + 1, up, right, row - 1)

    return search_rec(0, 0, len(matrix[0]) - 1, len(matrix) - 1)
发布了51 篇原创文章 · 获赞 4 · 访问量 3512

猜你喜欢

转载自blog.csdn.net/yhhuang17/article/details/105178257