Medium
题目描述
有一个 n x n 的 0 索引网格,其中埋藏着一些文物。给你整数 n 和一个 0 索引二维整数数组 artifacts,用来描述矩形文物的位置,其中 artifacts[i] = [r1i, c1i, r2i, c2i] 表示第 i 个文物埋藏在子网格中:
(r1i, c1i)是第i个文物的左上角单元格的坐标(r2i, c2i)是第i个文物的右下角单元格的坐标
你将会挖掘网格中的一些单元格并清除其中的泥土。如果单元格中埋有文物的一部分,那么该文物就会被发现。如果一个文物的所有部分都被发现,你就可以提取该文物。
给你一个 0 索引二维整数数组 dig,其中 dig[i] = [ri, ci] 表示你将会挖掘单元格 (ri, ci),请你返回你可以提取的文物数量。
测试用例保证:
- 没有两个文物重叠
- 每个文物最多覆盖 4 个单元格
dig中的条目都是唯一的
示例 1:
输入:n = 2, artifacts = [[0,0,0,0],[0,1,1,1]], dig = [[0,0],[0,1]]
输出:1
解释:不同颜色代表不同的文物。挖掘的单元格用网格中的 'D' 标记。
有 1 个文物可以提取,即红色文物。
蓝色文物在单元格 (1,1) 有一部分未被发现,所以我们无法提取它。
因此,返回 1。
示例 2:
输入:n = 2, artifacts = [[0,0,0,0],[0,1,1,1]], dig = [[0,0],[0,1],[1,1]]
输出:2
解释:红色和蓝色文物的所有部分都被发现(标记为 'D')并且可以提取,所以返回 2。
提示:
1 <= n <= 10001 <= artifacts.length, dig.length <= min(n², 10⁵)artifacts[i].length == 4dig[i].length == 20 <= r1i, c1i, r2i, c2i, ri, ci <= n - 1r1i <= r2ic1i <= c2i- 没有两个文物重叠
- 每个文物覆盖的单元格数最多为 4
dig中的条目都是唯一的
解题思路
这道题的核心思路是模拟挖掘过程,判断每个文物是否完全被挖掘出来。
解题思路:
标记挖掘位置:首先遍历所有挖掘位置,用哈希集合或二维数组标记哪些位置被挖掘了。这样可以在 O(1) 时间内查询某个位置是否被挖掘。
检查文物状态:对于每个文物,遍历它覆盖的所有单元格,检查是否都被挖掘了。文物的覆盖范围是从
(r1, c1)到(r2, c2)的矩形区域。计数完全挖掘的文物:如果一个文物的所有单元格都被挖掘,则计数器加一。
优化考虑:
- 使用哈希集合存储挖掘位置比二维数组更节省空间,因为挖掘位置可能稀疏
- 题目限制每个文物最多覆盖 4 个单元格,所以内层循环复杂度很小
时间复杂度分析:
- 构建挖掘位置集合:O(dig.length)
- 检查所有文物:O(artifacts.length × 4) = O(artifacts.length)
- 总时间复杂度:O(dig.length + artifacts.length)
代码实现
class Solution {
public:
int digArtifacts(int n, vector<vector<int>>& artifacts, vector<vector<int>>& dig) {
// 使用set存储已挖掘的位置
set<pair<int, int>> excavated;
for (auto& d : dig) {
excavated.insert({d[0], d[1]});
}
int count = 0;
// 检查每个文物是否完全被挖掘
for (auto& artifact : artifacts) {
int r1 = artifact[0], c1 = artifact[1];
int r2 = artifact[2], c2 = artifact[3];
bool canExtract = true;
// 检查文物覆盖的所有单元格
for (int r = r1; r <= r2; r++) {
for (int c = c1; c <= c2; c++) {
if (excavated.find({r, c}) == excavated.end()) {
canExtract = false;
break;
}
}
if (!canExtract) break;
}
if (canExtract) count++;
}
return count;
}
};
class Solution:
def digArtifacts(self, n: int, artifacts: List[List[int]], dig: List[List[int]]) -> int:
# 使用set存储已挖掘的位置
excavated = set((r, c) for r, c in dig)
count = 0
# 检查每个文物是否完全被挖掘
for r1, c1, r2, c2 in artifacts:
can_extract = True
# 检查文物覆盖的所有单元格
for r in range(r1, r2 + 1):
for c in range(c1, c2 + 1):
if (r, c) not in excavated:
can_extract = False
break
if not can_extract:
break
if can_extract:
count += 1
return count
public class Solution {
public int DigArtifacts(int n, int[][] artifacts, int[][] dig) {
// 使用HashSet存储已挖掘的位置
HashSet<(int, int)> excavated = new HashSet<(int, int)>();
foreach (int[] d in dig) {
excavated.Add((d[0], d[1]));
}
int count = 0;
// 检查每个文物是否完全被挖掘
foreach (int[] artifact in artifacts) {
int r1 = artifact[0], c1 = artifact[1];
int r2 = artifact[2], c2 = artifact[3];
bool canExtract = true;
// 检查文物覆盖的所有单元格
for (int r = r1; r <= r2; r++) {
for (int c = c1; c <= c2; c++) {
if (!excavated.Contains((r, c))) {
canExtract = false;
break;
}
}
if (!canExtract) break;
}
if (canExtract) count++;
}
return count;
}
}
var digArtifacts = function(n, artifacts, dig) {
// 使用Set存储已挖掘的位置
const excavated = new Set();
for (let [r, c] of dig) {
excavated.add(`${r},${c}`);
}
let count = 0;
// 检查每个文物是否完全被挖掘
for (let [r1, c1, r2, c2] of artifacts) {
let canExtract = true;
// 检查文物覆盖的所有单元格
for (let r = r1; r <= r2; r++) {
for (let c = c1; c <= c2; c++) {
if (!excavated.has(`${r},${c}`)) {
canExtract = false;
break;
}
}
if (!canExtract) break;
}
if (canExtract) count++;
}
return count;
};
复杂度分析
| 复杂度类型 | 复杂度 | 说明 |
|---|---|---|
| 时间复杂度 | O(D + A) | D 为挖掘位置数量,A 为文物数量,每个文物最多检查 4 个单元格 |
| 空间复杂度 | O(D) | 存储挖掘位置的哈希集合 |
相关题目
- . Maximal Square (Medium)