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
相关推荐
A923A2 分钟前
【洛谷刷题 | 第五天】
算法·字符串·递归·洛谷
Navigator_Z22 分钟前
LeetCode //C - 990. Satisfiability of Equality Equations
c语言·算法·leetcode
bbbb36522 分钟前
图算法的最优路径搜索与边界约束建模的技术7
算法
東雪木26 分钟前
编程算法学习——栈与队列算法
学习·算法·排序算法
CSDN_Colinw28 分钟前
C++中的工厂方法模式
开发语言·c++·算法
liulilittle31 分钟前
范围随机算法实现
开发语言·c++·算法·lua·c·js
2401_857918291 小时前
C++中的访问者模式实战
开发语言·c++·算法
elseif1231 小时前
CSP-S提高级大纲
开发语言·数据结构·c++·笔记·算法·大纲·考纲
熊猫_豆豆1 小时前
Python 基于Dlib和OpenCV实现人脸融合算法+代码
图像处理·python·算法·人脸融合
Book思议-1 小时前
【数据结构实战】双向链表:在指定位置插入数据
c语言·数据结构·算法·链表