LeetCode 题解工作台

矩阵查询可获得的最大分数

给你一个大小为 m x n 的整数矩阵 grid 和一个大小为 k 的数组 queries 。 找出一个大小为 k 的数组 answer ,且满足对于每个整数 queries[i] ,你从矩阵 左上角 单元格开始,重复以下过程: 如果 queries[i] 严格 大于你当前所处位置单元格,如果该单元…

category

7

题型

code_blocks

4

代码语言

hub

3

相关题

当前训练重点

困难 · 双·指针·invariant

bolt

答案摘要

根据题目描述我们知道,每个查询相互独立,查询的顺序不影响结果,并且题目要我们每次从左上角开始,统计所有可以访问的、且值小于当前查询值的单元格的个数。 因此,我们可以先对 `queries` 数组进行排序,然后从小到大依次处理每个查询。

Interview AiBox logo

Interview AiBox 实时 AI 助手,陪你讲清 双·指针·invariant 题型思路

试试 AiBox 面试助手arrow_forward
description

题目描述

给你一个大小为 m x n 的整数矩阵 grid 和一个大小为 k 的数组 queries

找出一个大小为 k 的数组 answer ,且满足对于每个整数 queries[i] ,你从矩阵 左上角 单元格开始,重复以下过程:

  • 如果 queries[i] 严格 大于你当前所处位置单元格,如果该单元格是第一次访问,则获得 1 分,并且你可以移动到所有 4 个方向(上、下、左、右)上任一 相邻 单元格。
  • 否则,你不能获得任何分,并且结束这一过程。

在过程结束后,answer[i] 是你可以获得的最大分数。注意,对于每个查询,你可以访问同一个单元格 多次

返回结果数组 answer

 

示例 1:

输入:grid = [[1,2,3],[2,5,7],[3,5,1]], queries = [5,6,2]
输出:[5,8,1]
解释:上图展示了每个查询中访问并获得分数的单元格。

示例 2:

输入:grid = [[5,2,1],[1,1,2]], queries = [3]
输出:[0]
解释:无法获得分数,因为左上角单元格的值大于等于 3 。

 

提示:

  • m == grid.length
  • n == grid[i].length
  • 2 <= m, n <= 1000
  • 4 <= m * n <= 105
  • k == queries.length
  • 1 <= k <= 104
  • 1 <= grid[i][j], queries[i] <= 106
lightbulb

解题思路

方法一:离线查询 + BFS + 优先队列(小根堆)

根据题目描述我们知道,每个查询相互独立,查询的顺序不影响结果,并且题目要我们每次从左上角开始,统计所有可以访问的、且值小于当前查询值的单元格的个数。

因此,我们可以先对 queries 数组进行排序,然后从小到大依次处理每个查询。

我们用优先队列(小根堆)维护当前访问到的最小单元格的值,用数组或哈希表 vis 记录当前单元格是否已经访问过。初始时,将左上角单元格的数据 (grid[0][0],0,0)(grid[0][0], 0, 0) 作为三元组加入优先队列,并将 vis[0][0] 置为 True

对于每个查询 queries[i],我们判断当前优先队列的最小值是否小于 queries[i],如果是,则将当前最小值弹出,累加计数器 cnt,并将当前单元格的上下左右四个单元格加入优先队列,注意要判断是否已经访问过。重复上述操作,直到当前优先队列的最小值大于等于 queries[i],此时 cnt 即为当前查询的答案。

时间复杂度 O(k×logk+m×nlog(m×n))O(k \times \log k + m \times n \log(m \times n)),空间复杂度 O(m×n)O(m \times n)。其中 mmnn 分别为网格的行数和列数,而 kk 为查询的个数。我们需要对 queries 数组进行排序,时间复杂度为 O(k×logk)O(k \times \log k)。矩阵中的每个单元格最多只会被访问一次,每一次入队和出队的时间复杂度为 O(log(m×n))O(\log(m \times n))。因此,总时间复杂度为 O(k×logk+m×nlog(m×n))O(k \times \log k + m \times n \log(m \times n))

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Solution:
    def maxPoints(self, grid: List[List[int]], queries: List[int]) -> List[int]:
        m, n = len(grid), len(grid[0])
        qs = sorted((v, i) for i, v in enumerate(queries))
        ans = [0] * len(qs)
        q = [(grid[0][0], 0, 0)]
        cnt = 0
        vis = [[False] * n for _ in range(m)]
        vis[0][0] = True
        for v, k in qs:
            while q and q[0][0] < v:
                _, i, j = heappop(q)
                cnt += 1
                for a, b in pairwise((-1, 0, 1, 0, -1)):
                    x, y = i + a, j + b
                    if 0 <= x < m and 0 <= y < n and not vis[x][y]:
                        heappush(q, (grid[x][y], x, y))
                        vis[x][y] = True
            ans[k] = cnt
        return ans
speed

复杂度分析

指标
时间O(k \log k + (n \cdot m) \log (n \cdot m) + k \cdot \alpha(n \cdot m))
空间O((n \cdot m) + k)
psychology

面试官常问的追问

外企场景
  • question_mark

    Tests understanding of two-pointer strategies in grid-based problems.

  • question_mark

    Assesses the ability to manage grid traversal with invariant tracking and efficient data structures.

  • question_mark

    Evaluates optimization skills when processing multiple queries in a grid setting.

warning

常见陷阱

外企场景
  • error

    Not leveraging the precomputation of queries, which leads to redundant computations.

  • error

    Incorrectly handling the grid traversal state, leading to errors in point calculation.

  • error

    Inefficient query handling that doesn't scale well with large inputs or multiple queries.

swap_horiz

进阶变体

外企场景
  • arrow_right_alt

    Consider handling grids with larger dimensions to test the efficiency of the solution.

  • arrow_right_alt

    Test with queries that are all smaller than the values in the grid to ensure the algorithm handles edge cases.

  • arrow_right_alt

    Consider implementing a dynamic programming approach instead of sorting for different performance trade-offs.

help

常见问题

外企场景

矩阵查询可获得的最大分数题解:双·指针·invariant | LeetCode #2503 困难