Medium
题目描述
在一个无限的 2D 平面上,你需要处理一系列查询。
给定一个正整数 k 和一个 2D 数组 queries,其中包含以下查询:
queries[i] = [x, y]:在平面上的坐标(x, y)处建造一个障碍物。保证在进行此查询时,该坐标处没有障碍物。
在每次查询后,你需要找到距离原点第 k 近的障碍物的距离。
返回一个整数数组 results,其中 results[i] 表示查询 i 后第 k 近的障碍物的距离,如果少于 k 个障碍物,则 results[i] == -1。
注意,最初平面上没有任何障碍物。
坐标为 (x, y) 的障碍物到原点的距离由 |x| + |y| 给出(曼哈顿距离)。
示例 1:
输入:queries = [[1,2],[3,4],[2,3],[-3,0]], k = 2
输出:[-1,7,5,3]
解释:
- 最初有 0 个障碍物。
- 查询 [1,2] 后,少于 2 个障碍物。
- 查询 [3,4] 后,距离分别为 3 和 7 的障碍物。
- 查询 [2,3] 后,距离分别为 3、5 和 7 的障碍物。
- 查询 [-3,0] 后,距离分别为 3、3、5 和 7 的障碍物。
示例 2:
输入:queries = [[5,5],[4,4],[3,3]], k = 1
输出:[10,8,6]
解释:
- 查询 [5,5] 后,有距离为 10 的障碍物。
- 查询 [4,4] 后,有距离为 8 和 10 的障碍物。
- 查询 [3,3] 后,有距离为 6、8 和 10 的障碍物。
约束条件:
1 <= queries.length <= 2 * 10^5- 所有
queries[i]都是唯一的 -10^9 <= queries[i][0], queries[i][1] <= 10^91 <= k <= 10^5
解题思路
这道题要求我们动态维护第 k 近的障碍物距离。关键思路是使用最大堆来维护当前最近的 k 个障碍物距离。
核心思想:
- 使用大小为 k 的最大堆,堆顶始终是这 k 个距离中的最大值
- 当堆的大小小于 k 时,直接添加新障碍物的距离
- 当堆的大小等于 k 时:
- 如果新距离小于堆顶(当前第 k 近的距离),则移除堆顶并添加新距离
- 否则忽略新距离,因为它不会影响第 k 近的结果
算法步骤:
- 对于每个查询,计算障碍物到原点的曼哈顿距离
|x| + |y| - 维护一个最大堆,确保堆中始终保存最近的 k 个距离
- 如果堆中元素少于 k 个,返回 -1;否则返回堆顶元素
这种方法的优势是能够高效地维护动态的第 k 小值,避免了每次都要对所有距离排序的开销。
推荐解法: 使用最大堆的解法,时间复杂度最优。
代码实现
class Solution {
public:
vector<int> resultsArray(vector<vector<int>>& queries, int k) {
vector<int> results;
priority_queue<int> maxHeap; // 最大堆
for (auto& query : queries) {
int distance = abs(query[0]) + abs(query[1]);
if (maxHeap.size() < k) {
maxHeap.push(distance);
} else if (distance < maxHeap.top()) {
maxHeap.pop();
maxHeap.push(distance);
}
if (maxHeap.size() < k) {
results.push_back(-1);
} else {
results.push_back(maxHeap.top());
}
}
return results;
}
};
class Solution:
def resultsArray(self, queries: List[List[int]], k: int) -> List[int]:
import heapq
results = []
max_heap = [] # 使用负数模拟最大堆
for x, y in queries:
distance = abs(x) + abs(y)
if len(max_heap) < k:
heapq.heappush(max_heap, -distance)
elif distance < -max_heap[0]:
heapq.heappop(max_heap)
heapq.heappush(max_heap, -distance)
if len(max_heap) < k:
results.append(-1)
else:
results.append(-max_heap[0])
return results
public class Solution {
public int[] ResultsArray(int[][] queries, int k) {
var results = new List<int>();
var maxHeap = new PriorityQueue<int, int>(Comparer<int>.Create((a, b) => b.CompareTo(a)));
foreach (var query in queries) {
int distance = Math.Abs(query[0]) + Math.Abs(query[1]);
if (maxHeap.Count < k) {
maxHeap.Enqueue(distance, distance);
} else if (distance < maxHeap.Peek()) {
maxHeap.Dequeue();
maxHeap.Enqueue(distance, distance);
}
if (maxHeap.Count < k) {
results.Add(-1);
} else {
results.Add(maxHeap.Peek());
}
}
return results.ToArray();
}
}
var resultsArray = function(queries, k) {
const maxHeap = [];
const results = [];
const insertMaxHeap = (val) => {
maxHeap.push(val);
let idx = maxHeap.length - 1;
while (idx > 0) {
const parentIdx = Math.floor((idx - 1) / 2);
if (maxHeap[idx] <= maxHeap[parentIdx]) break;
[maxHeap[idx], maxHeap[parentIdx]] = [maxHeap[parentIdx], maxHeap[idx]];
idx = parentIdx;
}
};
const removeMaxHeap = () => {
if (maxHeap.length === 0) return null;
if (maxHeap.length === 1) return maxHeap.pop();
const max = maxHeap[0];
maxHeap[0] = maxHeap.pop();
let idx = 0;
while (true) {
const leftChild = 2 * idx + 1;
const rightChild = 2 * idx + 2;
let largest = idx;
if (leftChild < maxHeap.length && maxHeap[leftChild] > maxHeap[largest]) {
largest = leftChild;
}
if (rightChild < maxHeap.length && maxHeap[rightChild] > maxHeap[largest]) {
largest = rightChild;
}
if (largest === idx) break;
[maxHeap[idx], maxHeap[largest]] = [maxHeap[largest], maxHeap[idx]];
idx = largest;
}
return max;
};
for (const [x, y] of queries) {
const distance = Math.abs(x) + Math.abs(y);
if (maxHeap.length < k) {
insertMaxHeap(distance);
} else if (distance < maxHeap[0]) {
removeMaxHeap();
insertMaxHeap(distance);
}
results.push(maxHeap.length === k ? maxHeap[0] : -1);
}
return results;
};
复杂度分析
| 复杂度类型 | 大小 |
|---|---|
| 时间复杂度 | O(n log k),其中 n 是查询次数,每次堆操作需要 O(log k) 时间 |
| 空间复杂度 | O(k),最大堆最多存储 k 个元素 |
相关题目
- . K Closest Points to Origin (Medium)