You are given a 0-indexed array heights
of positive integers, where heights[i]
represents the height of the i<sup>th</sup>
building.
If a person is in building i
, they can move to any other building j
if and only if i < j
and heights[i] < heights[j]
.
You are also given another array queries
where queries[i] = [a<sub>i</sub>, b<sub>i</sub>]
. On the i<sup>th</sup>
query, Alice is in building a<sub>i</sub>
while Bob is in building b<sub>i</sub>
.
Return an array ans
where ans[i]
is the index of the leftmost building where Alice and Bob can meet on the i<sup>th</sup>
query. If Alice and Bob cannot move to a common building on query i
, set ans[i]
to -1
.
For example:
heights = [6,4,8,5,2,7], queries = [[0,1],[0,3],[2,4],[3,4],[2,2]]
Output: [2,5,-1,5,2]
Explanation:
2
since heights[0] < heights[2]
and heights[1] < heights[2]
.5
since heights[0] < heights[5]
and heights[3] < heights[5]
.5
since heights[3] < heights[5]
and heights[4] < heights[5]
.Can you provide an algorithm with optimal time and space complexity to solve this problem?
The brute force approach involves iterating through all possible meeting points k
for each query (a, b)
and checking if both Alice (from building a
) and Bob (from building b
) can reach building k
. We need to ensure a < k
, heights[a] < heights[k]
, b < k
, and heights[b] < heights[k]
.
def solve():
heights = [6, 4, 8, 5, 2, 7]
queries = [[0, 1], [0, 3], [2, 4], [3, 4], [2, 2]]
def can_reach(start, end, heights):
return start < end and heights[start] < heights[end]
def find_meeting_point(a, b, heights):
for k in range(len(heights)):
if a < k and b < k and heights[a] < heights[k] and heights[b] < heights[k]:
return k
return -1
ans = []
for a, b in queries:
if a == b:
ans.append(a)
else:
ans.append(find_meeting_point(a, b, heights))
return ans
print(solve())
O(Q * N), where Q is the number of queries and N is the number of buildings (heights).
O(1), excluding the space to store the output.
Since the brute force solution has a time complexity of O(QN), let's think about pre-computation to improve performance. The constraints indicate that N and Q can both be up to 5 * 10^4, so an O(QN) solution might be too slow.
There aren't any obvious data structures to assist here. Essentially, for each query, we're looking for the smallest index k
such that k > a
, k > b
, heights[k] > heights[a]
, and heights[k] > heights[b]
. We can still solve this by looping from max(a, b) + 1
to N
but no precomputation makes it obviously faster.
def solve_optimized():
heights = [6, 4, 8, 5, 2, 7]
queries = [[0, 1], [0, 3], [2, 4], [3, 4], [2, 2]]
def find_meeting_point(a, b, heights):
start_index = max(a, b) + 1
for k in range(start_index, len(heights)):
if heights[a] < heights[k] and heights[b] < heights[k]:
return k
return -1
ans = []
for a, b in queries:
if a == b:
ans.append(a)
else:
ans.append(find_meeting_point(a, b, heights))
return ans
print(solve_optimized())
O(Q * N) in the worst case, but can be faster if a meeting point is found early. On average, performance should improve since we start searching from max(a,b) + 1
. However, the overall big O complexity is unchanged.
O(1), excluding the space to store the output.
a
.k
satisfies the conditions, return -1.While the O(Q*N) complexity seems unavoidable given the problem constraints, consider potential optimizations if the constraints were significantly larger:
i
, we could precompute the leftmost building j
such that heights[j] > heights[i]
for all i < j
. Then, for each query, we would lookup for a
and b
to determine a meet point.