You are given an integer n
, representing the number of rows in an n x 3
grid. Each cell in the grid can be painted with one of three colors: red, yellow, or green. The rules are:
Your task is to determine the total number of ways to paint the grid, modulo 10^9 + 7
.
Constraints:
1 <= n <= 5000
At first glance, you might think of generating all possible colorings and checking which ones are valid. However, with 3 colors and 3 columns per row, the number of possibilities grows exponentially with n
. This brute-force approach is not feasible for large n
.
Instead, we should look for patterns or states that allow us to efficiently compute the answer using dynamic programming. The key is to recognize that the coloring of each row only depends on the coloring of the previous row, and that there are limited valid colorings for a single row.
By classifying row colorings into patterns (based on how colors are arranged), we can keep track of how many ways each pattern can transition to the next row, and use this to build up the solution efficiently.
We break the problem into manageable subproblems using dynamic programming. Let's walk through the steps:
same
: Number of ways to paint up to row i
ending with a Type 1 (ABA) pattern.diff
: Number of ways to paint up to row i
ending with a Type 2 (ABC) pattern.new_same = same * 3 + diff * 2
new_diff = same * 2 + diff * 2
n
rows:
same
and diff
for each subsequent row.(same + diff) % (10^9 + 7)
.
Let's walk through the process for n = 2
(a 2x3 grid):
30 + 24 = 54
This matches the example in the problem statement.
Brute-force approach:
O(3^{3n})
(for each cell, 3 choices; for all n rows of 3 columns)O(1)
if not storing all coloringsO(n)
(one iteration per row)O(1)
(we only need the previous state, not the whole DP table)
The optimized approach is highly efficient and works for the maximum constraint n = 5000
.
class Solution:
def numOfWays(self, n: int) -> int:
MOD = 10 ** 9 + 7
same, diff = 6, 6 # same: ABA, diff: ABC
for _ in range(1, n):
new_same = (same * 3 + diff * 2) % MOD
new_diff = (same * 2 + diff * 2) % MOD
same, diff = new_same, new_diff
return (same + diff) % MOD
class Solution {
public:
int numOfWays(int n) {
const int MOD = 1e9 + 7;
long same = 6, diff = 6;
for (int i = 1; i < n; ++i) {
long new_same = (same * 3 + diff * 2) % MOD;
long new_diff = (same * 2 + diff * 2) % MOD;
same = new_same;
diff = new_diff;
}
return (same + diff) % MOD;
}
};
class Solution {
public int numOfWays(int n) {
int MOD = 1000000007;
long same = 6, diff = 6;
for (int i = 1; i < n; ++i) {
long new_same = (same * 3 + diff * 2) % MOD;
long new_diff = (same * 2 + diff * 2) % MOD;
same = new_same;
diff = new_diff;
}
return (int)((same + diff) % MOD);
}
}
var numOfWays = function(n) {
const MOD = 1e9 + 7;
let same = 6, diff = 6;
for (let i = 1; i < n; ++i) {
let new_same = (same * 3 + diff * 2) % MOD;
let new_diff = (same * 2 + diff * 2) % MOD;
same = new_same;
diff = new_diff;
}
return (same + diff) % MOD;
};
The key to solving the "Number of Ways to Paint N × 3 Grid" problem efficiently is recognizing the repeating patterns in row colorings and how they transition from one row to the next. By classifying rows into two types (ABA and ABC), and using dynamic programming to keep track of valid transitions, we reduce the problem from an exponential brute-force search to a simple linear recurrence. This approach is both elegant and highly performant, making it suitable for large inputs.