There is a city composed of n x n
blocks, where each block contains a single building shaped like a vertical square prism. You are given a 0-indexed n x n
integer matrix grid
where grid[r][c]
represents the height of the building located in the block at row r
and column c
.
A city's skyline is the outer contour formed by all the building when viewing the side of the city from a distance. The skyline from each cardinal direction north, east, south, and west may be different.
We are allowed to increase the height of any number of buildings by any amount (the amount can be different per building). The height of a 0
-height building can also be increased. However, increasing the height of a building should not affect the city's skyline from any cardinal direction.
Return the maximum total sum that the height of the buildings can be increased by without changing the city's skyline from any cardinal direction.
Example 1:
Input: grid = [[3,0,8,4],[2,4,5,7],[9,2,6,3],[0,3,1,0]] Output: 35 Explanation: The building heights are shown in the center of the above image. The skylines when viewed from each cardinal direction are drawn in red. The grid after increasing the height of buildings without affecting skylines is: gridNew = [ [8, 4, 8, 7], [7, 4, 7, 7], [9, 4, 8, 7], [3, 3, 3, 3] ]
Example 2:
Input: grid = [[0,0,0],[0,0,0],[0,0,0]] Output: 0 Explanation: Increasing the height of any building will result in the skyline changing.
Constraints:
n == grid.length
n == grid[r].length
2 <= n <= 50
0 <= grid[r][c] <= 100
When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
The problem asks us to increase the height of buildings in a city while maintaining the city's skyline from all four directions. A brute-force approach would be to try every possible height increase for each building, within the constraints of the skyline.
Here's how the algorithm would work step-by-step:
def max_increase_to_keep_city_skyline_brute_force(grid):
city_size = len(grid)
max_total_increase = 0
for building_row in range(city_size):
for building_col in range(city_size):
original_height = grid[building_row][building_col]
for potential_increase in range(city_size * city_size): #try every height
new_height = original_height + potential_increase
# Check if the new height violates skyline constraints.
is_valid = True
# Check north/south skyline
max_north_south = 0
for i in range(city_size):
max_north_south = max(max_north_south, grid[i][building_col] if i != building_row else new_height)
for i in range(city_size):
if i != building_row and grid[i][building_col] > new_height and max_north_south != new_height:
is_valid = False
break
# Check east/west skyline
max_east_west = 0
for j in range(city_size):
max_east_west = max(max_east_west, grid[building_row][j] if j != building_col else new_height)
for j in range(city_size):
if j != building_col and grid[building_row][j] > new_height and max_east_west != new_height:
is_valid = False
break
if is_valid:
#If valid, calculate the total increase
total_increase = 0
temp_grid = [row[:] for row in grid] #create a temporary grid
temp_grid[building_row][building_col] = new_height
for row in range(city_size):
for col in range(city_size):
total_increase += (temp_grid[row][col] - grid[row][col])
max_total_increase = max(max_total_increase, total_increase)
else:
break # if not valid, move to next building
return max_total_increase
The goal is to increase the height of buildings in a city grid without changing the skyline. The optimal strategy involves finding the tallest building in each row and column, and then increasing each building's height up to the minimum of its row's tallest and its column's tallest.
Here's how the algorithm would work step-by-step:
def max_increase_keeping_skyline(grid):
number_of_rows = len(grid)
number_of_columns = len(grid[0])
# Find the tallest building in each row.
tallest_in_each_row = [max(row) for row in grid]
# Find the tallest building in each column.
tallest_in_each_column = [max(grid[i][j] for i in range(number_of_rows)) for j in range(number_of_columns)]
total_increase = 0
for row_index in range(number_of_rows):
for column_index in range(number_of_columns):
# Determine the maximum allowable height.
max_allowable_height = min(tallest_in_each_row[row_index], tallest_in_each_column[column_index])
if grid[row_index][column_index] < max_allowable_height:
total_increase += max_allowable_height - grid[row_index][column_index]
return total_increase
Case | How to Handle |
---|---|
Null or empty grid | Return 0 if the grid is null or empty, as no increase is possible. |
Grid with only one row/column | Calculate the maximum value in the row/column and compute the increase for each cell. |
Grid with all identical values | All cells can be increased to the identical value, resulting in a total increase equal to the number of cells times 0. |
Large grid with large integer values | Ensure calculations (especially when summing increases) do not cause integer overflow and use appropriate data types. |
Grid with negative numbers | The problem statement implicitly implies non-negative values, but if negative values are allowed, the skyline calculation must correctly handle them by finding min values in rows/cols instead of max. |
Grid where all cells are already at the maximum possible value for their row and column | The increase for all cells will be 0, thus returning 0. |
Non-square grid (m x n, m != n) | Ensure the skyline calculation correctly handles the different dimensions when calculating the maximum values for rows and columns. |
Grid with very large dimensions approaching memory limits | Algorithm should have a low memory footprint, accessing elements iteratively to avoid loading the entire grid into memory if possible. |