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

Powered by:NEFU AB-IN

Link

文章目录

  • [2940. 找到 Alice 和 Bob 可以相遇的建筑](#2940. 找到 Alice 和 Bob 可以相遇的建筑)

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. st表 + 二分

    问题相当于计算区间 [b+1,n−1] 中第一个大于 v=heights[a] 的高度的位置,那么二分区间即可,二分判断这个区间的最大值是否大于v

    线段树此题TLE,无在线操作的,就不用线段树解决RMQ问题

  2. 离线 + 最小堆

    离线的意思,就是把询问分组,不按照输入的顺序一个个回答,按自己定义的顺序回答

    整理好询问后,从左到右遍历建筑,如果发现当前 idx 建筑高度 > 之前需要回答的一个询问的建筑高度,那么这个询问的答案就是 idx

    需要一个最小堆去维护这些询问,每次取出最小的 heights[i],去和 heights[idx] 比较

    如果 heights[i]< heights[idx] 就立刻回答(答案就是 idx)# 否则就不再回答(因为最小堆中其余元素都是 >= 堆顶的)

    还需要在堆中记录询问的编号

代码

python 复制代码
'''
Author: NEFU AB-IN
Date: 2024-08-10 17:31:58
FilePath: \LeetCode\2940\2940.py
LastEditTime: 2024-08-10 18:19:01
'''
# 3.8.19 import
import random
from collections import Counter, defaultdict, deque
from datetime import datetime, timedelta
from functools import lru_cache, reduce
from heapq import heapify, heappop, heappush, nlargest, nsmallest
from itertools import combinations, compress, permutations, starmap, tee
from math import ceil, comb, fabs, floor, gcd, hypot, log, perm, sqrt
from string import ascii_lowercase, ascii_uppercase
from sys import exit, setrecursionlimit, stdin
from typing import Any, Callable, Dict, List, Optional, Tuple, TypeVar, Union

# Constants
TYPE = TypeVar('TYPE')
N = int(2e5 + 10)
M = int(20)
INF = int(1e12)
OFFSET = int(100)
MOD = int(1e9 + 7)

# Set recursion limit
setrecursionlimit(int(2e9))


class Arr:
    array = staticmethod(lambda x=0, size=N: [x() if callable(x) else x for _ in range(size)])
    array2d = staticmethod(lambda x=0, rows=N, cols=M: [Arr.array(x, cols) for _ in range(rows)])
    graph = staticmethod(lambda size=N: [[] for _ in range(size)])


class Math:
    max = staticmethod(lambda a, b: a if a > b else b)
    min = staticmethod(lambda a, b: a if a < b else b)


class IO:
    input = staticmethod(lambda: stdin.readline().rstrip("\r\n"))
    read = staticmethod(lambda: map(int, IO.input().split()))
    read_list = staticmethod(lambda: list(IO.read()))


class Std:
    class SparseTable:
        def __init__(self, data: list, func=lambda x, y: x | y):
            """Initialize the Sparse Table with the given data and function."""
            self.func = func
            self.st = [list(data)]
            i, n = 1, len(self.st[0])
            while 2 * i <= n:
                pre = self.st[-1]
                self.st.append([func(pre[j], pre[j + i]) for j in range(n - 2 * i + 1)])
                i <<= 1

        def query(self, begin: int, end: int):
            """Query the combined result over the interval [begin, end]."""
            lg = (end - begin + 1).bit_length() - 1
            return self.func(self.st[lg][begin], self.st[lg][end - (1 << lg) + 1])

# --------------------------------------------------------------- Division line ------------------------------------------------------------------


class Solution:
    def leftmostBuildingQueries(self, heights: List[int], queries: List[List[int]]) -> List[int]:
        n = len(heights)
        st = Std.SparseTable(heights, Math.max)

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

            val = Math.max(heights[a], heights[b])
            l, r = b, n - 1
            while l < r:
                mid = l + r >> 1
                if st.query(b, mid) > val:
                    r = mid
                else:
                    l = mid + 1
            ans.append(r if heights[r] > val else -1)
        return ans
python 复制代码
class Solution:
    def leftmostBuildingQueries(self, heights: List[int], queries: List[List[int]]) -> List[int]:
        ans = [-1] * len(queries)
        qs = [[] for _ in heights]
        for i, (a, b) in enumerate(queries):
            if a > b:
                a, b = b, a  # 保证 a <= b
            if a == b or heights[a] < heights[b]:
                ans[i] = b  # a 直接跳到 b
            else:
                qs[b].append((heights[a], i))  # 离线询问

        h = []
        for i, x in enumerate(heights):
            while h and h[0][0] < x:
                # 堆顶的 heights[a] 可以跳到 heights[i]
                ans[heappop(h)[1]] = i
            for q in qs[i]:
                heappush(h, q)  # 后面再回答
        return ans
相关推荐
地平线开发者2 小时前
SparseDrive 模型导出与性能优化实战
算法·自动驾驶
董董灿是个攻城狮3 小时前
大模型连载2:初步认识 tokenizer 的过程
算法
地平线开发者3 小时前
地平线 VP 接口工程实践(一):hbVPRoiResize 接口功能、使用约束与典型问题总结
算法·自动驾驶
罗西的思考3 小时前
AI Agent框架探秘:拆解 OpenHands(10)--- Runtime
人工智能·算法·机器学习
HXhlx7 小时前
CART决策树基本原理
算法·机器学习
Wect7 小时前
LeetCode 210. 课程表 II 题解:Kahn算法+DFS 双解法精讲
前端·算法·typescript
颜酱8 小时前
单调队列:滑动窗口极值问题的最优解(通用模板版)
javascript·后端·算法
Gorway14 小时前
解析残差网络 (ResNet)
算法
拖拉斯旋风14 小时前
LeetCode 经典算法题解析:优先队列与广度优先搜索的巧妙应用
算法
Wect14 小时前
LeetCode 207. 课程表:两种解法(BFS+DFS)详细解析
前端·算法·typescript