目录
题目解析 | 查找二维矩阵中所有坐标的第 K 大前缀异或值
题目描述
给你一个大小为 m x n
的二维矩阵 matrix
,矩阵中的元素均为非负整数。定义坐标 (a, b)
的 目标值为:
以 (a, b)
为右下角,左上角固定为 (0, 0)
的子矩阵中所有元素的异或结果。
换句话说,目标值是对所有满足 0 <= i <= a < m
且 0 <= j <= b < n
的元素 matrix[i][j]
做异或运算后的结果。
请你找出矩阵中所有坐标的目标值中第 k
大的值。k
从 1 开始计数。
问题拆解与解题分析
1. 异或的性质
- 异或运算有结合律和交换律
- 异或自身为零:
x ^ x = 0
- 任何数与零异或结果是其自身:
x ^ 0 = x
这些性质使得计算前缀异或和成为可能,类似前缀和的思想。
2. 什么是“前缀异或数组”
我们定义一个二维数组 prefix
,其中
即 (0,0)
到 (i,j)
的矩阵子区域内所有元素的异或和。
这样一来,目标值 (a,b)
就可以直接通过 prefix[a][b]
得到。
3. 计算 prefix[i][j]
如何计算 prefix
?
观察发现:
prefix[i-1][j]
和prefix[i][j-1]
是分别从上和左获得的异或值prefix[i-1][j-1]
因为加了两次,需要异或回去- 再异或当前元素
matrix[i][j]
4. 收集所有目标值,排序返回第 k 大
计算完成所有的 prefix[i][j]
,把它们放进列表里。
对列表进行降序排序后,取第 k 个元素即可。
代码实现(Python)
from typing import List
class Solution:
def kthLargestValue(self, matrix: List[List[int]], k: int) -> int:
m, n = len(matrix), len(matrix[0])
prefix = [[0] * n for _ in range(m)]
values = []
for i in range(m):
for j in range(n):
top = prefix[i-1][j] if i > 0 else 0
left = prefix[i][j-1] if j > 0 else 0
top_left = prefix[i-1][j-1] if i > 0 and j > 0 else 0
prefix[i][j] = top ^ left ^ top_left ^ matrix[i][j]
values.append(prefix[i][j])
values.sort(reverse=True)
return values[k-1]
复杂度分析
时间复杂度:
计算前缀异或需要遍历矩阵所有元素,时间为 O(m*n)
,排序所有目标值(共有 m*n
个)需要 O(m*n log(m*n))
,因此总时间复杂度为:
- O(m×nlog(m×n))
- 空间复杂度:
需要存储prefix
数组和values
列表,均为O(m*n)
。
优化建议
当 k
比较小,但矩阵很大时,排序所有元素显得效率不高。可以使用大小为 k
的最小堆维护 top k 大的元素:
- 遍历所有
prefix[i][j]
- 将元素放入最小堆,堆大小超过
k
时弹出最小元素 - 最终堆顶即为第 k 大元素
这样,维护堆的时间复杂度为 O(m*n * log k)
,相比完全排序可能更快。
示例说明
举个例子:
matrix = [
[5, 2],
[1, 6]
]
k = 2
- 计算 prefix 数组:
i\j | 0 | 1 |
0 | 5 | 5 ^ 2 = 7 |
1 | 5 ^ 1 = 4 | 5 ^ 2 ^ 1 ^ 6 = 3 |
所以 prefix = [[5,7],[4,3]]
- 所有目标值是
[5,7,4,3]
- 降序排列是
[7,5,4,3]
- 第 2 大是
5
总结
本题关键在于利用前缀异或数组,将复杂的矩阵区域异或查询降维为 O(1) 的查询,极大提升计算效率。
常规做法是计算所有目标值并排序,但在大规模数据下,堆优化可以显著降低时间开销。