Maximum Building Height

Hard
Watch on YouTube ↗

Solution

class Solution {
    public int maxBuilding(int n, int[][] nums) {

        // Let m = number of restricted buildings
        // Time:  O(m log m) for sorting + O(m) for the passes
        // Space: O(m)

        Arrays.sort(nums, (a, b) -> Integer.compare(a[0], b[0]));

        int len = nums.length;
        if (len == 0) return n - 1; // No restrictions, max height bounded only by edges

        // Check if the last building already has a restriction
        boolean isLast = nums[len - 1][0] == n;

        // Total points to process: restrictions + building 1 + (building n if not already included)
        int m = len + 1 + (isLast ? 0 : 1);

        int[][] h = new int[m][2]; // h[i] = {position, max height at position}
        h[0][0] = 1;
        h[0][1] = 0; // Building 1 has height 0

        // Left-to-right pass: propagate max possible height forward, capped by restrictions
        for (int i = 0; i < len; i++) {
            int diff = nums[i][0] - h[i][0];
            int ht = h[i][1] + diff;
            h[i + 1][0] = nums[i][0];
            h[i + 1][1] = Math.min(ht, nums[i][1]);
        }

        // Add building n if it wasn't part of the restrictions
        if (!isLast) {
            int diff = n - h[len][0];
            int ht = h[len][1] + diff;
            h[len + 1][0] = n;
            h[len + 1][1] = Math.min(ht, n - 1);
        }

        // Right-to-left pass: propagate max possible height backward, capped similarly
        for (int i = m - 2; i >= 0; i--) {
            int diff = h[i + 1][0] - h[i][0];
            int ht = h[i + 1][1] + diff;
            h[i][1] = Math.min(h[i][1], ht);
        }

        // For each consecutive pair of capped points, compute the max peak height achievable between them
        int ans = 0;
        for (int i = 1; i < m; i++) {
            int left = h[i - 1][0];
            int right = h[i][0];
            int h1 = h[i - 1][1];
            int h2 = h[i][1];

            // Peak height formula: average the "slack" distance and add to the taller endpoint
            int max = (right - left - Math.abs(h1 - h2)) / 2 + Math.max(h1, h2);
            ans = Math.max(ans, max);
        }

        return ans;
    }
}