You are given two integers height and width representing the height and width of a brick wall respectively. The wall is made up of rows of bricks of the same height 1.
You are given an array bricks where bricks[i] is the width of the ith brick. You can use an unlimited number of bricks of each width.
You want to build the wall such that it satisfies the following conditions:
width.bricks.Return the number of ways to build a sturdy brick wall. Since the answer may be very large, return it modulo 109 + 7.
A brick wall is considered sturdy if there is no vertical line going through all rows of bricks. In other words, there should not exist any vertical line from top to bottom that crosses all rows without crossing any bricks.
Example 1:
Input: height = 3, width = 2, bricks = [1,2] Output: 3 Explanation: The possible ways to build the wall are: [1, 1] [2] [2] [1, 1] [1, 1] [1, 1]
Since all of the walls have a vertical line going through all of the rows, the number of sturdy brick walls is 3.
Example 2:
Input: height = 1, width = 1, bricks = [1] Output: 0 Explanation: Since we cannot build any row of bricks with width equals to 1, the answer is 0.
Constraints:
1 <= height <= 1001 <= width <= 101 <= bricks.length <= 101 <= bricks[i] <= widthWhen 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 brute force approach to building a sturdy brick wall involves trying every conceivable wall configuration. It's like physically building every possible wall, one at a time, to see which ones meet the criteria. We will exhaustively explore all combinations.
Here's how the algorithm would work step-by-step:
def number_of_ways_to_build_sturdy_brick_wall_brute_force(height, width): total_sturdy_walls = 0
def is_wall_sturdy(wall): for column_index in range(1, width): crack_found = True for row_index in range(height): row = wall[row_index]
total_width = 0
for brick_width in row:
total_width += brick_width
if total_width == column_index:
crack_found = False
break if crack_found:
break if crack_found:
return True
return False
def generate_rows(current_row, current_width): if current_width == width:
return [current_row]
if current_width > width:
return []
row_arrangements = [] for brick_width in range(1, width + 1): remaining_width = current_width + brick_width
if remaining_width <= width: new_row = current_row + [brick_width]
row_arrangements.extend(generate_rows(new_row, remaining_width)) return row_arrangements def generate_walls(current_wall): if len(current_wall) == height:
if is_wall_sturdy(current_wall): return 1 else:
return 0 # Generate all possible rows for the next level row_arrangements = generate_rows([], 0) sturdy_wall_count = 0 # Try to add it to the wall and recurse for row in row_arrangements:
sturdy_wall_count += generate_walls(current_wall + [row]) return sturdy_wall_count # Count all the possible walls total_sturdy_walls = generate_walls([]) return total_sturdy_wallsThe goal is to find the number of ways to build a sturdy brick wall of a given height and width, where a sturdy wall has vertical cracks that don't align across rows. The key is to use dynamic programming to avoid recomputing redundant calculations and only considering valid row configurations.
Here's how the algorithm would work step-by-step:
def number_of_ways_to_build_wall(height, width):
def get_valid_row_configurations(width):
valid_configurations = []
def find_configurations(current_width, current_configuration):
if current_width == width:
valid_configurations.append(tuple(current_configuration))
return
if current_width > width:
return
for brick_width in range(1, width):
find_configurations(current_width + brick_width, current_configuration + [brick_width])
find_configurations(0, [])
# Only keep configurations that sum up to the full width.
valid_configurations = [config for config in valid_configurations if sum(config) == width]
valid_configurations = list(set(valid_configurations))
return valid_configurations
valid_row_configurations = get_valid_row_configurations(width)
number_of_configurations = len(valid_row_configurations)
def are_rows_compatible(row1, row2):
crack_positions_row1 = set()
current_position = 0
for brick_width in row1:
current_position += brick_width
if current_position < width:
crack_positions_row1.add(current_position)
crack_positions_row2 = set()
current_position = 0
for brick_width in row2:
current_position += brick_width
if current_position < width:
crack_positions_row2.add(current_position)
# Check if any crack positions are the same.
return not bool(crack_positions_row1.intersection(crack_positions_row2))
# dp[i][j] is ways to build wall of height i ending with config j.
dp = [[0] * number_of_configurations for _ in range(height + 1)]
# Base case: height 1, each configuration has one way.
for j in range(number_of_configurations):
dp[1][j] = 1
# Iterate to build up the DP table
for i in range(2, height + 1):
for j in range(number_of_configurations):
# Check for compatibility
for k in range(number_of_configurations):
if are_rows_compatible(valid_row_configurations[j], valid_row_configurations[k]):
dp[i][j] += dp[i - 1][k]
# Sum of all ways to end with a given config
total_ways = sum(dp[height])
return total_ways| Case | How to Handle |
|---|---|
| Zero wall height or zero wall width | Return 0 ways as a wall with no height or width is not possible. |
| Wall height of 1 | The number of ways is equivalent to the number of valid row configurations, which can be precomputed efficiently. |
| Wall width of 1 | There is only one way to build the wall regardless of height since each row must have a brick of width 1. |
| Large wall height and width (scaling) | Use dynamic programming with memoization to avoid redundant calculations and achieve better time complexity (avoiding exponential explosion). |
| No valid row configurations possible for given width | Return 0 ways as it's impossible to construct any valid wall. |
| Integer overflow when calculating number of ways | Use modulo operator with a prime number (e.g., 10^9 + 7) to prevent overflow. |
| All bricks are of size 1 | Check all configurations and return results based on problem statement. |
| Highly skewed brick size distribution (e.g., only 1 and width-1) | The algorithm must efficiently enumerate possible row configurations even with skewed distributions by potentially pruning invalid branches early. |