离线处理查询,LeetCode 2940. 找到 Alice 和 Bob 可以相遇的建筑

一、题目

1、题目描述

给你一个下标从 0 开始的正整数数组 heights ,其中 heights[i] 表示第 i 栋建筑的高度。

如果一个人在建筑 i ,且存在 i < j 的建筑 j 满足 heights[i] < heights[j] ,那么这个人可以移动到建筑 j 。

给你另外一个数组 queries ,其中 queries[i] = [ai, bi] 。第 i 个查询中,Alice 在建筑 ai ,Bob 在建筑 bi 。

请你能返回一个数组 ans ,其中 ans[i] 是第 i 个查询中,Alice 和 Bob 可以相遇的 最左边的建筑 。如果对于查询 i ,Alice  Bob 不能相遇,令 ans[i] 为 -1 。

2、接口描述

python3
 ​
class Solution:
    def leftmostBuildingQueries(self, heights: List[int], queries: List[List[int]]) -> List[int]:

3、原题链接

2940. Find Building Where Alice and Bob Can Meet


二、解题报告

1、思路分析

比较直观的思路是:线段树二分 或者 ST表预处理+二分

但是这种直接借助数据结构的方式不利于思维的训练,这种题目往往可以使用离线处理 + 数据结构维护,往难了出可以主席树,整体二分,莫队……比较常见的就是先离线处理查询,再按照某种遍历顺序处理巧妙化解问题

本题考虑两种做法:最小堆 / 单调栈+二分

F1 最小堆

查询(a, b)(a <= b),如果 height[a] < height[b] 或者a == b,那么答案就是b

对于一般情况:

将查询放到右端点b处,记保存每个下标作为右端点的查询,即 找到b右边大于height[a] 的最靠近b的索引

然后我们顺序遍历heights,最小堆保存遍历过的下标的所有以其为右端点的查询

如果堆顶 查询 值小于当前遍历到的height,那么弹出堆顶,维护答案

F2 单调栈+二分

和上一个方法预处理查询方法相同

我们考虑每个查询要找到右边第一个大于指定值的索引

我们可以倒序遍历heights,维护一个单调栈,栈顶到栈底递增,那么遍历过程中,如果有询问,栈顶到栈底第一个大于的就是答案

2、复杂度

时间复杂度: O(n + qlogq)空间复杂度:O(n)

3、代码详解

F1 最小堆
class Solution:
    def leftmostBuildingQueries(self, heights: List[int], queries: List[List[int]]) -> List[int]:
        n = len(heights)
        q = [[] for _ in range(n)]
        ans = [-1] * len(queries)
        for i, (a, b) in enumerate(queries):
            if a > b:
                a, b = b, a
            if a == b or heights[b] > heights[a]:
                ans[i] = b
            else:
                q[b].append((heights[a], i))

        pq = []
        for i, x in enumerate(heights):
            while pq and pq[0][0] < x:
                ans[heappop(pq)[1]] = i
            for Q in q[i]:
                heappush(pq, Q)
        return ans
F2 单调栈二分
class Solution:
    def leftmostBuildingQueries(self, heights: List[int], queries: List[List[int]]) -> List[int]:
        n = len(heights)
        q = [[] for _ in range(n)]
        ans = [-1] * len(queries)
        for i, (a, b) in enumerate(queries):
            if a > b:
                a, b = b, a
            if a == b or heights[b] > heights[a]:
                ans[i] = b
            else:
                q[b].append((heights[a], i))
        st = []
        for i in range(len(heights) - 1, -1, -1):
            for h, qi in q[i]:
                j = bisect_left(st, -h, key=lambda i:-heights[i])
                if j:
                    ans[qi] = st[j - 1]
            while st and heights[i] >= heights[st[-1]]:
                st.pop()
            st.append(i)
        return ans

                
  • 8
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

EQUINOX1

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值