You are given two integers m and n. Consider an m x n grid where each cell is initially white. You can paint each cell red, green, or blue. All cells must be painted.
Return the number of ways to color the grid with no two adjacent cells having the same color. Since the answer can be very large, return it modulo 109 + 7.
Example 1:
Input: m = 1, n = 1 Output: 3 Explanation: The three possible colorings are shown in the image above.
Example 2:
Input: m = 1, n = 2 Output: 6 Explanation: The six possible colorings are shown in the image above.
Example 3:
Input: m = 5, n = 5 Output: 580986
Constraints:
1 <= m <= 51 <= n <= 1000When 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:
We need to color a grid where each cell can be one of three colors. The brute force method involves trying every single possible color combination for the entire grid. We will then check if each coloring meets the problem's specific rules.
Here's how the algorithm would work step-by-step:
def count_valid_colorings_brute_force(number_of_rows, number_of_columns):
total_valid_colorings = 0
grid = [[0] * number_of_columns for _ in range(number_of_rows)]
def is_valid_coloring(row_index, column_index):
# Check if the current cell has a different color than its neighbors
if row_index > 0 and grid[row_index][column_index] == grid[row_index - 1][column_index]:
return False
if column_index > 0 and grid[row_index][column_index] == grid[row_index][column_index - 1]:
return False
return True
def solve(row_index, column_index):
nonlocal total_valid_colorings
# When we hit past the last cell, count the valid coloring.
if row_index == number_of_rows:
total_valid_colorings += 1
return
for color in range(1, 4):
grid[row_index][column_index] = color
# Check if current coloring is valid, proceed if so.
if is_valid_coloring(row_index, column_index):
next_row_index = row_index
next_column_index = column_index + 1
if next_column_index == number_of_columns:
next_row_index += 1
next_column_index = 0
solve(next_row_index, next_column_index)
# Start the recursive calls from the first cell.
solve(0, 0)
return total_valid_coloringsWe can solve this problem efficiently using a clever approach called dynamic programming. We will break the big grid into smaller problems, solving each row based on the solution of the previous row to avoid redoing work.
Here's how the algorithm would work step-by-step:
def count_ways_to_paint_grid(number_of_rows, number_of_columns):
number_of_colors = 3
# Generate all possible valid colorings for a single row
def generate_valid_row_colorings(number_of_columns, number_of_colors):
if number_of_columns == 0:
return [[]]
row_colorings = []
for color in range(number_of_colors):
for previous_row_coloring in generate_valid_row_colorings(number_of_columns - 1, number_of_colors):
if not previous_row_coloring or previous_row_coloring[-1] != color:
row_colorings.append(previous_row_coloring + [color])
return row_colorings
valid_row_colorings = generate_valid_row_colorings(number_of_columns, number_of_colors)
number_of_valid_row_colorings = len(valid_row_colorings)
# Initialize DP table to store the number of ways to paint the grid up to each row
dp_table = [[0] * number_of_valid_row_colorings for _ in range(number_of_rows)]
# Base case: the first row can be colored in any valid way
for i in range(number_of_valid_row_colorings):
dp_table[0][i] = 1
# Iterate through the rows, building up the DP table
for row_index in range(1, number_of_rows):
# Iterate through the valid colorings for the current row
for current_row_coloring_index in range(number_of_valid_row_colorings):
# Iterate through the valid colorings for the previous row
for previous_row_coloring_index in range(number_of_valid_row_colorings):
# Check if the current row coloring is compatible with the previous row coloring
is_compatible = True
for column_index in range(number_of_columns):
if valid_row_colorings[current_row_coloring_index][column_index] == \
valid_row_colorings[previous_row_coloring_index][column_index]:
is_compatible = False
break
# If the colorings are compatible, update the DP table
if is_compatible:
dp_table[row_index][current_row_coloring_index] += \
dp_table[row_index - 1][previous_row_coloring_index]
# Sum up the number of ways to color the last row for all valid colorings
total_ways_to_paint = 0
for coloring_index in range(number_of_valid_row_colorings):
total_ways_to_paint += dp_table[number_of_rows - 1][coloring_index]
return total_ways_to_paint
# The main function to solve the grid coloring problem
def painting_grid_with_three_colors(number_of_rows, number_of_columns):
# Handle invalid input cases
if number_of_rows <= 0 or number_of_columns <= 0:
return 0
# Use dynamic programming to count the ways
result = count_ways_to_paint_grid(number_of_rows, number_of_columns)
return result| Case | How to Handle |
|---|---|
| Zero rows or columns (n=0 or m=0) | Return 1, as there's only one way to paint an empty grid (do nothing). |
| One row (n=1) | The number of ways to color each column is 3, and we multiply it m times so return 3^m. |
| One column (m=1) | The number of ways to color each row is 3, and we multiply it n times so return 3^n. |
| n and m are both small (e.g., n=1, m=1, n=2, m=2) | The base cases must be handled directly (e.g., n=1, m=1 returns 3). |
| n and m are both large (e.g., n=100, m=100) | Implement dynamic programming to avoid exponential time complexity, storing intermediate results. |
| Integer overflow when calculating the total number of ways | Use modulo operator with a large prime number at each step to prevent overflow. |
| All valid colorings exist | The algorithm should correctly enumerate all possible valid colorings or their count if needed. |
| Consecutive rows or columns have identical colorings | The DP algorithm should consider the restrictions and avoid such consecutive identical colorings. |