Taro Logo

Find Building Where Alice and Bob Can Meet

Hard
Amazon logo
Amazon
Topics:
Arrays

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:

  • 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.

Can you provide an algorithm with optimal time and space complexity to solve this problem?

Solution


Naive Solution

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].

Code (Python)

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())

Time Complexity

O(Q * N), where Q is the number of queries and N is the number of buildings (heights).

Space Complexity

O(1), excluding the space to store the output.

Optimal Solution

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.

Code (Python)

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())

Time Complexity

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.

Space Complexity

O(1), excluding the space to store the output.

Edge Cases

  • a == b: Alice and Bob are in the same building; return the index a.
  • No meeting point: If no building k satisfies the conditions, return -1.
  • Empty heights array: Should return an appropriate error code or handle the edge case gracefully (e.g., return an empty array). This case isn't applicable based on the problem's constraints.

Further Optimization Considerations

While the O(Q*N) complexity seems unavoidable given the problem constraints, consider potential optimizations if the constraints were significantly larger:

  1. Precomputed Lookup Tables: If we had memory to spare, for each building 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.
  2. Binary Search Tree (BST): Construct a BST of building heights and their indices, it can speed up the search for meeting points.