2940. Find Building Where Alice and Bob Can Meet
2940. Find Building Where Alice and Bob Can Meet
Difficulty: Hard
Topics: Array
, Binary Search
, Stack
, Binary Indexed Tree
, Segment Tree
, Heap (Priority Queue)
, Monotonic Stack
You are given a 0-indexed array heights
of positive integers, where heights[i]
represents the height of the ith
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] = [ai, bi]
. On the ith
query, Alice is in building ai
while Bob is in building bi
.
Return an array ans
where ans[i]
is the index of the leftmost building where Alice and Bob can meet on the ith
query. If Alice and Bob cannot move to a common building on query i
, set ans[i]
to -1
.
Example 1:
- Input: 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: In the first query, Alice and Bob can move to building 2 since heights[0] < heights[2] and heights[1] < heights[2].
- In the second query, Alice and Bob can move to building 5 since heights[0] < heights[5] and heights[3] < heights[5].
- In the third query, Alice cannot meet Bob since Alice cannot move to any other building.
- In the fourth query, Alice and Bob can move to building 5 since heights[3] < heights[5] and heights[4] < heights[5].
- In the fifth query, Alice and Bob are already in the same building.
- For ans[i] != -1, It can be shown that ans[i] is the leftmost building where Alice and Bob can meet.
- For ans[i] == -1, It can be shown that there is no building where Alice and Bob can meet.
Example 2:
- Input: heights = [5,3,8,2,6,1,4,6], queries = [[0,7],[3,5],[5,2],[3,0],[1,6]]
- Output: [7,6,-1,4,6]
-
Explanation: In the first query, Alice can directly move to Bob's building since heights[0] < heights[7].
- In the second query, Alice and Bob can move to building 6 since heights[3] < heights[6] and heights[5] < heights[6].
- In the third query, Alice cannot meet Bob since Bob cannot move to any other building.
- In the fourth query, Alice and Bob can move to building 4 since heights[3] < heights[4] and heights[0] < heights[4].
- In the fifth query, Alice can directly move to Bob's building since heights[1] < heights[6].
- For ans[i] != -1, It can be shown that ans[i] is the leftmost building where Alice and Bob can meet.
- For ans[i] == -1, It can be shown that there is no building where Alice and Bob can meet.
Constraints:
1 <= heights.length <= 5 * 104
1 <= heights[i] <= 109
1 <= queries.length <= 5 * 104
queries[i] = [ai, bi]
0 <= ai, bi <= heights.length - 1
Hint:
- For each query
[x, y]
, ifx > y
, swapx
andy
. Now, we can assume thatx <= y
. - For each query
[x, y]
, ifx == y
orheights[x] < heights[y]
, then the answer isy
sincex ≤ y
. - Otherwise, we need to find the smallest index
t
such thaty < t
andheights[x] < heights[t]
. Note thatheights[y] <= heights[x]
, soheights[x] < heights[t]
is a sufficient condition. - To find index
t
for each query, sort the queries in descending order ofy
. Iterate over the queries while maintaining a monotonic stack which we can binary search over to find indext
.
Solution:
The problem requires determining the leftmost building where Alice and Bob can meet given their starting buildings and movement rules. Each query involves finding a meeting point based on building heights. This is challenging due to the constraints on movement and the need for efficient computation.
Key Points
- Alice and Bob can move to another building if its height is strictly greater than the current building.
- For each query, find the leftmost valid meeting point, or return
-1
if no such building exists. - The constraints demand a solution better than a naive O(n²) approach.
Approach
-
Observations:
- If
a == b
, Alice and Bob are already at the same building. - If
heights[a] < heights[b]
, Bob's building is the meeting point. - Otherwise, find the smallest building index
t > b
where:heights[a] < heights[t]
-
heights[b] <= heights[t]
(asb
is already less thana
in height comparison).
- If
-
Optimization Using Monotonic Stack:
- A monotonic stack helps efficiently track the valid buildings Alice and Bob can move to. Buildings are added to the stack in a way that ensures heights are in decreasing order, enabling fast binary searches.
-
Query Sorting:
- Sort the queries in descending order of
b
to process buildings with larger indices first. This ensures that we build the stack efficiently as we move from higher to lower indices.
- Sort the queries in descending order of
-
Binary Search on Stack:
- For each query, use binary search on the monotonic stack to find the smallest index
t
that satisfies the conditions.
- For each query, use binary search on the monotonic stack to find the smallest index
Plan
- Sort queries based on the larger of the two indices (
b
) in descending order. - Traverse the array backward while maintaining a monotonic stack of valid indices.
- For each query, check trivial cases (
a == b
orheights[a] < heights[b]
). - For non-trivial cases, use the stack to find the leftmost valid building via binary search.
- Return the results in the original query order.
Solution Steps
-
Preprocess Queries:
- Ensure
a <= b
in each query for consistency. - Sort queries by
b
in descending order.
- Ensure
-
Iterate Through Queries:
- Maintain a monotonic stack as we traverse the array.
- For each query:
- If
a == b
, the answer isb
. - If
heights[a] < heights[b]
, the answer isb
. - Otherwise, use the stack to find the smallest valid index
t > b
.
- If
-
Binary Search on Stack:
- Use binary search to quickly find the smallest index
t
on the stack that satisfiesheights[t] > heights[a]
.
- Use binary search to quickly find the smallest index
-
Restore Original Order:
- Map results back to the original query indices.
Return Results.
Let's implement this solution in PHP: 2940. Find Building Where Alice and Bob Can Meet
<?php
/**
* @param Integer[] $heights
* @param Integer[][] $queries
* @return Integer[]
*/
function leftmostBuildingQueries($heights, $queries) {
...
...
...
/**
* go to ./solution.php
*/
}
/**
* @param $queries
* @return array
*/
private function getIndexedQueries($queries) {
...
...
...
/**
* go to ./solution.php
*/
}
/**
* @param $stack
* @param $a
* @param $heights
* @return mixed|null
*/
private function findUpperBound($stack, $a, $heights) {
...
...
...
/**
* go to ./solution.php
*/
}
class IndexedQuery {
public $queryIndex;
public $a; // Alice's index
public $b; // Bob's index
/**
* @param $queryIndex
* @param $a
* @param $b
*/
public function __construct($queryIndex, $a, $b) {
$this->queryIndex = $queryIndex;
$this->a = $a;
$this->b = $b;
}
}
// Test the function
$heights = [6, 4, 8, 5, 2, 7];
$queries = [[0, 1], [0, 3], [2, 4], [3, 4], [2, 2]];
print_r(leftmostBuildingQueries($heights, $queries));
$heights = [5, 3, 8, 2, 6, 1, 4, 6];
$queries = [[0, 7], [3, 5], [5, 2], [3, 0], [1, 6]];
print_r(leftmostBuildingQueries($heights, $queries));
?>
Explanation:
-
Sorting Queries: The queries are sorted by
b
in descending order to process larger indices first, which allows us to update our monotonic stack as we process. - Monotonic Stack: The stack is used to keep track of building indices where Alice and Bob can meet. We only keep buildings that have a height larger than any previously seen buildings in the stack.
-
Binary Search: When answering each query, we use binary search to efficiently find the smallest index
t
where the conditions are met.
Example Walkthrough
Input:
heights = [6,4,8,5,2,7]
queries = [[0,1],[0,3],[2,4],[3,4],[2,2]]
Process:
-
Sort Queries:
- Indexed queries:
[(2,4), (3,4), (0,3), (0,1), (2,2)]
- Indexed queries:
-
Build Monotonic Stack:
- Start at the highest index and add indices to the stack:
- At index 5: Stack =
[5]
- At index 4: Stack =
[5, 4]
- ...
- At index 5: Stack =
- Start at the highest index and add indices to the stack:
-
Query Processing:
- For query
[0,1]
,heights[0] < heights[1]
: Result = 2. - ...
- For query
Output:
[2, 5, -1, 5, 2]
Time Complexity
-
Query Sorting:
O(Q log Q)
where Q is the number of queries. -
Monotonic Stack Construction:
O(N)
where N is the length ofheights
. -
Binary Search for Each Query:
O(Q log N)
.
Overall: O(N + Q log (Q + N))
.
Output for Example
Input:
$heights = [6, 4, 8, 5, 2, 7];
$queries = [[0, 1], [0, 3], [2, 4], [3, 4], [2, 2]];
Output:
print_r(findBuilding($heights, $queries)); // [2, 5, -1, 5, 2]
This approach efficiently handles large constraints by leveraging a monotonic stack and binary search. It ensures optimal query processing while maintaining correctness.
Contact Links
If you found this series helpful, please consider giving the repository a star on GitHub or sharing the post on your favorite social networks 😍. Your support would mean a lot to me!
If you want more helpful content like this, feel free to follow me: