Medium
题目描述
给你一个整数 n 和一个下标从 0 开始的二维数组 queries ,其中 queries[i] = [typei, indexi, vali] 。
一开始,给你一个下标从 0 开始的 n x n 矩阵,所有元素均为 0 。每一个查询,你需要执行以下操作之一:
- 如果
typei == 0,将第indexi行 的所有元素变为vali,覆盖任何之前的值。 - 如果
typei == 1,将第indexi列 的所有元素变为vali,覆盖任何之前的值。
请你返回执行完所有查询后,矩阵中所有整数的和。
示例 1:
输入:n = 3, queries = [[0,0,1],[1,2,2],[0,2,3],[1,0,4]]
输出:23
解释:上图描述了每个查询以后矩阵的状态。所有查询执行完以后,矩阵元素之和为 23 。
示例 2:
输入:n = 3, queries = [[0,0,4],[0,1,2],[1,0,1],[0,2,3],[1,2,1]]
输出:17
解释:上图描述了每个查询以后矩阵的状态。所有查询执行完以后,矩阵元素之和为 17 。
提示:
1 <= n <= 10^41 <= queries.length <= 5 * 10^4queries[i].length == 30 <= typei <= 10 <= indexi < n0 <= vali <= 10^5
解题思路
这道题的关键在于理解操作的覆盖性质。由于后面的操作会覆盖前面的操作结果,我们需要逆序处理查询。
核心思路:
- 逆序遍历:从最后一个查询开始处理,这样能确保我们处理的是每个位置的最终值
- 记录已处理的行列:使用集合记录已经被操作过的行和列,避免重复计算
- 计算贡献:当遇到一个未处理过的行/列操作时:
- 行操作:影响该行中所有未被列操作覆盖的位置,贡献为
val × (n - 已处理列数) - 列操作:影响该列中所有未被行操作覆盖的位置,贡献为
val × (n - 已处理行数)
- 行操作:影响该行中所有未被列操作覆盖的位置,贡献为
为什么逆序有效?
- 最后执行的操作具有最高优先级,不会被覆盖
- 一旦某行/列被处理过,之前对该行/列的操作都无效
- 通过逆序遍历,我们能准确计算每个操作对最终结果的实际贡献
时间复杂度O(m),空间复杂度O(n),其中m为查询数量。
代码实现
class Solution {
public:
long long matrixSumQueries(int n, vector<vector<int>>& queries) {
unordered_set<int> seenRows, seenCols;
long long sum = 0;
for (int i = queries.size() - 1; i >= 0; i--) {
int type = queries[i][0], index = queries[i][1], val = queries[i][2];
if (type == 0) { // 行操作
if (seenRows.find(index) == seenRows.end()) {
seenRows.insert(index);
sum += (long long)val * (n - seenCols.size());
}
} else { // 列操作
if (seenCols.find(index) == seenCols.end()) {
seenCols.insert(index);
sum += (long long)val * (n - seenRows.size());
}
}
}
return sum;
}
};
class Solution:
def matrixSumQueries(self, n: int, queries: List[List[int]]) -> int:
seen_rows = set()
seen_cols = set()
total_sum = 0
for type_val, index, val in reversed(queries):
if type_val == 0: # 行操作
if index not in seen_rows:
seen_rows.add(index)
total_sum += val * (n - len(seen_cols))
else: # 列操作
if index not in seen_cols:
seen_cols.add(index)
total_sum += val * (n - len(seen_rows))
return total_sum
public class Solution {
public long MatrixSumQueries(int n, int[][] queries) {
HashSet<int> seenRows = new HashSet<int>();
HashSet<int> seenCols = new HashSet<int>();
long sum = 0;
for (int i = queries.Length - 1; i >= 0; i--) {
int type = queries[i][0], index = queries[i][1], val = queries[i][2];
if (type == 0) { // 行操作
if (!seenRows.Contains(index)) {
seenRows.Add(index);
sum += (long)val * (n - seenCols.Count);
}
} else { // 列操作
if (!seenCols.Contains(index)) {
seenCols.Add(index);
sum += (long)val * (n - seenRows.Count);
}
}
}
return sum;
}
}
var matrixSumQueries = function(n, queries) {
let rowSet = new Set();
let colSet = new Set();
let sum = 0;
for (let i = queries.length - 1; i >= 0; i--) {
let [type, index, val] = queries[i];
if (type === 0) {
if (!rowSet.has(index)) {
rowSet.add(index);
sum += val * (n - colSet.size);
}
} else {
if (!colSet.has(index)) {
colSet.add(index);
sum += val * (n - rowSet.size);
}
}
}
return sum;
};
复杂度分析
| 复杂度 | 分析 |
|---|---|
| 时间复杂度 | O(m),其中 m 为查询数量,需要遍历所有查询一次 |
| 空间复杂度 | O(n),最坏情况下需要存储所有行和列的索引 |
相关题目
. Range Sum Query 2D - Mutable (Medium)
. Range Addition II (Easy)