leetcode 2940: 找到 Alice 和 Bob 可以相遇的建筑

题目描述

给你一个下标从 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 。

示例 1:

输入:heights = [6,4,8,5,2,7], queries = [[0,1],[0,3],[2,4],[3,4],[2,2]]
输出:[2,5,-1,5,2]
解释:第一个查询中,Alice 和 Bob 可以移动到建筑 2 ,因为 heights[0] < heights[2] 且 heights[1] < heights[2] 。
第二个查询中,Alice 和 Bob 可以移动到建筑 5 ,因为 heights[0] < heights[5] 且 heights[3] < heights[5] 。
第三个查询中,Alice 无法与 Bob 相遇,因为 Alice 不能移动到任何其他建筑。
第四个查询中,Alice 和 Bob 可以移动到建筑 5 ,因为 heights[3] < heights[5] 且 heights[4] < heights[5] 。
第五个查询中,Alice 和 Bob 已经在同一栋建筑中。
对于 ans[i] != -1 ,ans[i] 是 Alice 和 Bob 可以相遇的建筑中最左边建筑的下标。
对于 ans[i] == -1 ,不存在 Alice 和 Bob 可以相遇的建筑。

示例 2:

输入:heights = [5,3,8,2,6,1,4,6], queries = [[0,7],[3,5],[5,2],[3,0],[1,6]]
输出:[7,6,-1,4,6]
解释:第一个查询中,Alice 可以直接移动到 Bob 的建筑,因为 heights[0] < heights[7] 。
第二个查询中,Alice 和 Bob 可以移动到建筑 6 ,因为 heights[3] < heights[6] 且 heights[5] < heights[6] 。
第三个查询中,Alice 无法与 Bob 相遇,因为 Bob 不能移动到任何其他建筑。
第四个查询中,Alice 和 Bob 可以移动到建筑 4 ,因为 heights[3] < heights[4] 且 heights[0] < heights[4] 。
第五个查询中,Alice 可以直接移动到 Bob 的建筑,因为 heights[1] < heights[6] 。
对于 ans[i] != -1 ,ans[i] 是 Alice 和 Bob 可以相遇的建筑中最左边建筑的下标。
对于 ans[i] == -1 ,不存在 Alice 和 Bob 可以相遇的建筑。

提示:

  • 1 <= heights.length <= 5 * 104
  • 1 <= heights[i] <= 109
  • 1 <= queries.length <= 5 * 104
  • queries[i] = [ai, bi]
  • 0 <= ai, bi <= heights.length - 1

解题思路

方法一:线段树


思路与算法

代码

class Solution:
    def leftmostBuildingQueries(self, heights: List[int], queries: List[List[int]]) -> List[int]:
        n = len(heights)
        zd = [0] * (n * 4)

        def build(l, r, rt, heights):
            if l == r:
                zd[rt] = heights[l - 1]
                return

            mid = (l + r) // 2
            build(l, mid, rt << 1, heights)
            build(mid + 1, r, rt << 1 | 1, heights)
            zd[rt] = max(zd[rt << 1], zd[rt << 1 | 1])

        def query(pos, val, l, r, rt):
            if val >= zd[rt]:
                return 0
            if l == r:
                return l
            mid = (l + r) // 2
            if pos <= mid:
                res = query(pos, val, l, mid, rt << 1)
                if res != 0:
                    return res
            return query(pos, val, mid + 1, r, rt << 1 | 1)

        build(1, n, 1, heights)
        m = len(queries)
        ans = [0] * m
        for i in range(m):
            a, b = queries[i]
            if a > b:
                a, b = b, a
            if a == b or heights[a] < heights[b]:
                ans[i] = b
                continue
            ans[i] = query(b + 1, heights[a], 1, n, 1) - 1
        return ans

算法复杂度分析

  • 时间复杂度:O(mlogn),其中n 表示数组 heights 的长度,m 表示查询的长度。

  • 空间复杂度:O(n)。

方法二:离线 + 二分单调栈

思路与算法

和方法一相同,先对每一次查询进行预处理使得 a<b。如果 heights[a]<heights[b],那么可直接得到答案为 b。假设 heights[a]>=heights[b],那么答案一定在 b 的右边。可以将查询离线处理,从后往前枚举,维护一个从大到小的单调栈 st。对于每一个 b,在单调栈中二分找到第一个大于 heights[a] 的即可。

代码示例

class Solution:
    def leftmostBuildingQueries(self, heights: List[int], queries: List[List[int]]) -> List[int]:
        n = len(heights)
        m = len(queries)
        query = [[] for _ in range(n)]
        ans = [-1] * m
        st = []

        for i in range(m):
            a, b = queries[i]
            if a > b:
                a, b = b, a
            if a == b or heights[a] < heights[b]:
                ans[i] = b
                continue
            query[b].append((i, heights[a]))

        top = -1
        for i in range(n - 1, -1, -1):
            for q, val in query[i]:
                if top == -1 or heights[st[0]] <= val:
                    ans[q] = -1
                    continue

                l, r = 0, top
                while l <= r:
                    mid = (l + r) // 2
                    if heights[st[mid]] > val:
                        l = mid + 1
                    else:
                        r = mid - 1
                ans[q] = st[r]

            while top >= 0 and heights[st[top]] <= heights[i]:
                st.pop()
                top -= 1
            st.append(i)
            top += 1

        return ans

复杂度分析

  • 时间复杂度:O(mlogn),其中n 表示数组 heights 的长度,m 表示查询的长度。
  • 空间复杂度:O(n+m),其中单调栈最长为 n,查询最多有 m 个。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

科技之歌

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

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

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

打赏作者

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

抵扣说明:

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

余额充值