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

Powered by:NEFU AB-IN

Link

文章目录

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

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

题意

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

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

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

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

思路

题意就是找两个点,坐标大的点的下标(包括自己)的右边,哪个值比这两个点的最大值大,找出这个值的下标,并返回最靠左的

  1. st表 + 二分

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

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

  2. 离线 + 最小堆

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

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

    需要一个最小堆去维护这些询问,每次取出最小的 heightsi,去和 heightsidx 比较

    如果 heightsi< heightsidx 就立刻回答(答案就是 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
相关推荐
飞Link5 小时前
什么是 AirSim?一文读懂无人机仿真平台
python·算法·无人机
一去不复返的通信er7 小时前
贪心算法-合并区间(LeetCode 56)
算法·leetcode·贪心算法
Shaoshing8 小时前
LeetCode100 49. 字母异位词分组
java·算法
YFJ_mily8 小时前
第二届区块链技术与基础模型国际学术会议(BTFM2027)
算法·区块链·能源·智能系统·rdlink研发家·机器人自动化
汤姆宝库8 小时前
收官深拆:第一性原理、产业电网与未来推演
大数据·人工智能·算法
moshuying10 小时前
块扩散 + GDN 改造:Clover 把「并行生成」塞进了 Agent 的长上下文里
前端·算法
没落之王11 小时前
历史系统建模:宋初太祖太宗「再立天庭」秩序重构推演
人工智能·算法·重构
INGNIGHT11 小时前
91 · 最小调整代价(序列dp)
数据结构·算法·leetcode
moshuying11 小时前
扩散模型开始写代码、开网页了:350 亿参数,速度比 Jev 快一倍
前端·算法