python 矩阵中寻找就接近的目标值 (矩阵-中等)含源码(八)

问题说明(含示例)

问题描述 :给定一个 m x n 的矩阵(元素为浮点数),矩阵具有每行从左到右升序、每列从上到下升序的特性。需搜索矩阵中与目标值 target 最接近的数值 ,并返回该数值及其所在的行号列号(行号和列号从 0 开始)。

示例:现有矩阵:

复制代码
[
 [1,  5,  9, 13, 17],
 [2,  6, 10, 14, 18],
 [3,  7, 11, 15, 19],
 [4,  8, 12, 16, 20]
]
  1. 输入:target = 5.1输出:[5, 0, 1]解释:5 与 5.1 的差值为 0.1,是矩阵中最小的差值,其位置为第 0 行第 1 列。

  2. 输入:target = 11.7输出:[12, 3, 2]解释:12 与 11.7 的差值为 0.3,是最小差值,位置为第 3 行第 2 列。

  3. 输入:target = 100输出:[20, 3, 4]解释:矩阵中最大元素为 20,与 100 的差值最小,位置为第 3 行第 4 列。

解题关键

利用矩阵 "每行升序、每列升序 " 的特性,采用右上角起点搜索法 ,高效缩小搜索范围,避免暴力遍历(暴力法时间复杂度 O(mn),此方法优化至 O(m + n))。核心思路:

  1. 起点选择 :从矩阵右上角(i=0, j=cols-1)开始搜索,该位置是当前行的最大值、当前列的最小值,便于快速判断搜索方向。
  2. 搜索方向
    • 若当前元素 matrix[i][j] < target:说明当前行左侧元素均小于 target,需向下移动(i += 1),寻找更大的元素;
    • 若当前元素 matrix[i][j] > target:说明当前列下方元素均大于 target,需向左移动(j -= 1),寻找更小的元素;
  3. 记录最接近值 :在搜索过程中,实时计算当前元素与 target 的差值,更新 "最小差值" 及对应的元素值、行号、列号。
  4. 终止条件 :当 i 超出矩阵行数或 j 小于 0 时,搜索结束,返回记录的最接近值信息。

对应代码

python 复制代码
class Solution(object):
    def searchMatrix(self, matrix, target):
        """
        :type matrix: List[List[float]]
        :type target: float
        :rtype: List
        """
        if not matrix or not matrix[0]:  # 处理空矩阵或者第一行为空的矩阵
            return []
        
        rows = len(matrix)
        cols = len(matrix[0])
        
        # 初始化起点为右上角
        i, j = 0, cols - 1
        min_diff = float('inf')  # 最小差值,初始为无穷大
        res_val = None           # 最接近的数值
        res_row = -1             # 最接近数值的行号
        res_col = -1             # 最接近数值的列号
        
        while i < rows and j >= 0:
            current = matrix[i][j]
            current_diff = abs(current - target)  # 当前差值
            
            # 更新最小差值及结果
            if current_diff < min_diff:
                min_diff = current_diff
                res_val = current
                res_row = i
                res_col = j
            
            # 若差值为0,直接返回(已找到最接近值)
            if min_diff == 0:
                return [res_val, res_row, res_col]
            
            # 调整搜索方向
            if current < target:
                i += 1  # 当前元素偏小,向下寻找更大值
            else:
                j -= 1  # 当前元素偏大,向左寻找更小值
        
        return [res_val, res_row, res_col]
    

对应的基础知识

实现该算法需掌握以下基础概念与操作:

  1. 二维列表的访问与遍历

    • 矩阵在 Python 中以二维列表表示,matrix[i][j] 访问第 i 行第 j 列的元素;
    • 通过 len(matrix) 获取行数(外层列表长度),len(matrix[0]) 获取列数(内层列表长度)。
  2. 条件判断与方向调整

    • 核心逻辑 if current < target: i += 1 else: j -= 1 利用矩阵有序性,通过比较当前元素与目标值,动态调整搜索方向,避免无效遍历。
  3. 差值计算与最小值更新

    • abs(current - target) 计算当前元素与目标值的绝对值差值;
    • 通过 if current_diff < min_diff 实时更新 "最小差值" 及对应元素信息,确保最终结果是全局最接近值。
  4. 循环与边界控制

    • 循环条件 i < rows and j >= 0 确保搜索范围在矩阵内(i 不超过行数,j 不小于 0);
    • 当循环终止时,已遍历所有可能的 "潜在接近值",直接返回记录的结果。

对应的进阶知识

该问题的解决涉及算法优化与矩阵特性利用的进阶思想:

  1. 时间复杂度优化

    • 暴力法需遍历矩阵所有元素(O(mn)),而本算法最多移动 m + n 步(从右上角到左下角的最坏路径),时间复杂度降至 O(m + n),尤其适合大规模矩阵(如 m, n = 10^4 时,效率提升显著)。
  2. 起点选择的科学性

    • 选择右上角(或左下角)作为起点的核心原因是:该位置是 "行最大值" 和 "列最小值" 的交点,能通过一次比较明确排除一行或一列的元素(例如 current < target 时,当前行所有元素均小于 target,可直接排除)。
    • 若选择左上角或右下角作为起点,则无法通过一次比较排除整行或整列,会增加无效搜索步骤。
  3. 边界情况的隐性处理

    • target 小于矩阵所有元素时:搜索会一直向左移动,最终停在左上角元素(最小元素),符合预期;
    • target 大于矩阵所有元素时:搜索会一直向下移动,最终停在右下角元素(最大元素),符合预期;
    • 当矩阵中存在与 target 相等的元素时:min_diff 会变为 0,触发提前返回,减少不必要的搜索。
  4. 与二分查找的对比

    • 对于每行单独二分查找(时间复杂度 O(m log n)),本算法在 mn 接近时更优(O(m + n) 优于 O(m log n));
    • 核心差异:二分查找依赖 "完全有序"(如每行是前一行的延续),而本算法仅利用 "行内、列内有序" 的弱条件,适用范围更广。

编程思维与启示

  1. "特性驱动" 的算法设计 :面对有序数据结构(如本题的矩阵),不要急于暴力遍历,而是先观察其有序特性(行 / 列升序),思考如何利用特性减少搜索范围。本题正是通过 "右上角元素是行最大、列最小" 的特性,设计出 O(m + n) 的高效算法。

  2. "关键起点" 的选择逻辑:复杂问题的突破口往往在于找到一个 "能简化决策" 的起点。右上角作为起点,每次比较都能明确排除一行或一列,这种 "非此即彼" 的决策逻辑,是减少无效操作的核心。

  3. "实时更新" 的贪心思想:在搜索过程中,通过实时比较并更新 "最小差值",确保每一步都保留当前最优解,最终自然得到全局最优解。这种 "贪心" 策略避免了存储所有可能解再比较的额外空间开销。

  4. "边界先行" 的健壮性意识 :代码开篇即处理空矩阵的情况(if not matrix or not matrix[0]),体现了 "先防御、再逻辑" 的编程习惯。提前处理异常输入,能避免后续代码因索引错误或无效计算崩溃。

  5. "空间优化" 的潜意识 :算法仅使用常数个变量(i, j, min_diff 等)存储中间结果,未依赖额外的数据结构(如列表存储所有元素),体现了对空间复杂度的优化意识,尤其适合大规模数据场景。

相关推荐
cliproxydaili2 小时前
代理IP+账号矩阵:Cliproxy与TGX Account如何赋能品牌全球化表达?
网络协议·tcp/ip·矩阵
豆沙沙包?2 小时前
2025年--Lc170--H289. 生命游戏(矩阵)--Java版
java·游戏·矩阵
可爱的秋秋啊2 小时前
简单网站编写
开发语言·前端
冬夜戏雪2 小时前
[学习日记][springboot 1-7][leetcode 6道]
java·开发语言·学习
Hello.Reader2 小时前
Flink 状态模式演进(State Schema Evolution)从原理到落地的一站式指南
python·flink·状态模式
红纸2812 小时前
Subword算法之WordPiece、Unigram与SentencePiece
人工智能·python·深度学习·神经网络·算法·机器学习·自然语言处理
QX_hao2 小时前
【Go】--数据类型
开发语言·后端·golang
红纸2812 小时前
Subword分词方法的BPE与BBPE
人工智能·python·深度学习·神经网络·自然语言处理
Metaphor6922 小时前
Java 创建 Word 文档:实现高效文档生成
经验分享