跳转至

3275. 第 K 近障碍物查询

题目描述

有一个无限大的二维平面。

给你一个正整数 k ,同时给你一个二维数组 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]

解释:

最初,不存在障碍物。

  • queries[0] 之后,少于 2 个障碍物。
  • queries[1] 之后, 两个障碍物距离原点的距离分别为 3 和 7 。
  • queries[2] 之后,障碍物距离原点的距离分别为 3 ,5 和 7 。
  • queries[3] 之后,障碍物距离原点的距离分别为 3,3,5 和 7 。

示例 2:

输入:queries = [[5,5],[4,4],[3,3]], k = 1

输出:[10,8,6]

解释:

  • queries[0] 之后,只有一个障碍物,距离原点距离为 10 。
  • queries[1] 之后,障碍物距离原点距离分别为 8 和 10 。
  • queries[2] 之后,障碍物距离原点的距离分别为 6, 8 和10 。

 

提示:

  • 1 <= queries.length <= 2 * 105
  • 所有 queries[i] 互不相同。
  • -109 <= queries[i][0], queries[i][1] <= 109
  • 1 <= k <= 105

解法

方法一:优先队列(大根堆)

我们可以使用一个优先队列(大根堆)来维护离原点最近的 $k$ 个障碍物。

遍历 $\textit{queries}$,每次计算 $x$ 和 $y$ 的绝对值之和,然后将其加入优先队列。如果优先队列的大小超过 $k$,则弹出堆顶元素。如果当前优先队列的大小等于 $k$,则将堆顶元素加入答案数组,否则将 $-1$ 加入答案数组。

遍历结束后,返回答案数组即可。

时间复杂度 $O(n \times \log k)$,空间复杂度 $O(k)$。其中 $n$ 为数组 $\textit{queries}$ 的长度。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
class Solution:
    def resultsArray(self, queries: List[List[int]], k: int) -> List[int]:
        ans = []
        pq = []
        for i, (x, y) in enumerate(queries):
            heappush(pq, -(abs(x) + abs(y)))
            if i >= k:
                heappop(pq)
            ans.append(-pq[0] if i >= k - 1 else -1)
        return ans
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
class Solution {
    public int[] resultsArray(int[][] queries, int k) {
        int n = queries.length;
        int[] ans = new int[n];
        PriorityQueue<Integer> pq = new PriorityQueue<>(Collections.reverseOrder());
        for (int i = 0; i < n; ++i) {
            int x = Math.abs(queries[i][0]) + Math.abs(queries[i][1]);
            pq.offer(x);
            if (i >= k) {
                pq.poll();
            }
            ans[i] = i >= k - 1 ? pq.peek() : -1;
        }
        return ans;
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
class Solution {
public:
    vector<int> resultsArray(vector<vector<int>>& queries, int k) {
        vector<int> ans;
        priority_queue<int> pq;
        for (const auto& q : queries) {
            int x = abs(q[0]) + abs(q[1]);
            pq.push(x);
            if (pq.size() > k) {
                pq.pop();
            }
            ans.push_back(pq.size() == k ? pq.top() : -1);
        }
        return ans;
    }
};
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
func resultsArray(queries [][]int, k int) (ans []int) {
    pq := &hp{}
    for _, q := range queries {
        x := abs(q[0]) + abs(q[1])
        pq.push(x)
        if pq.Len() > k {
            pq.pop()
        }
        if pq.Len() == k {
            ans = append(ans, pq.IntSlice[0])
        } else {
            ans = append(ans, -1)
        }
    }
    return
}

func abs(x int) int {
    if x < 0 {
        return -x
    }
    return x
}

type hp struct{ sort.IntSlice }

func (h hp) Less(i, j int) bool { return h.IntSlice[i] > h.IntSlice[j] }
func (h *hp) Push(v any)        { h.IntSlice = append(h.IntSlice, v.(int)) }
func (h *hp) Pop() any {
    a := h.IntSlice
    v := a[len(a)-1]
    h.IntSlice = a[:len(a)-1]
    return v
}
func (h *hp) push(v int) { heap.Push(h, v) }
func (h *hp) pop() int   { return heap.Pop(h).(int) }
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
function resultsArray(queries: number[][], k: number): number[] {
    const pq = new MaxPriorityQueue();
    const ans: number[] = [];
    for (const [x, y] of queries) {
        pq.enqueue(Math.abs(x) + Math.abs(y));
        if (pq.size() > k) {
            pq.dequeue();
        }
        ans.push(pq.size() === k ? pq.front().element : -1);
    }
    return ans;
}

评论