class Solution:
def leftmostBuildingQueries(self, heights: List[int], queries: List[List[int]]) -> List[int]:
比较直观的思路是:线段树二分 或者 ST表预处理+二分
但是这种直接借助数据结构的方式不利于思维的训练,这种题目往往可以使用离线处理 + 数据结构维护,往难了出可以主席树,整体二分,莫队……比较常见的就是先离线处理查询,再按照某种遍历顺序处理巧妙化解问题
本题考虑两种做法:最小堆 / 单调栈+二分
F1 最小堆
查询(a, b)(a <= b),如果 height[a] < height[b] 或者a == b,那么答案就是b
对于一般情况:
将查询放到右端点b处,记保存每个下标作为右端点的查询,即 找到b右边大于height[a] 的最靠近b的索引
然后我们顺序遍历heights,最小堆保存遍历过的下标的所有以其为右端点的查询
如果堆顶 查询 值小于当前遍历到的height,那么弹出堆顶,维护答案
F2 单调栈+二分
和上一个方法预处理查询方法相同
我们考虑每个查询要找到右边第一个大于指定值的索引
我们可以倒序遍历heights,维护一个单调栈,栈顶到栈底递增,那么遍历过程中,如果有询问,栈顶到栈底第一个大于的就是答案
时间复杂度: O(n + qlogq)空间复杂度:O(n)
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
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
因篇幅问题不能全部显示,请点此查看更多更全内容