↓Skip to main content
  1. LeetCode/

LeetCode 1411: Number of Ways to Paint N × 3 Grid

·2 mins· ·
LeetCode Hard Dynamic-Programming State-Machine Graph-Coloring
Wei Yi Chung
Author
Wei Yi Chung
Working at the contributing of open source, distributed systems, and data engineering.
Table of Contents

Meta Data
#

Difficulty: hard First Attempt: 2026-07-05

  • Submissions: Accepted ×2 (brute-force enumeration → pattern classes)

Approach
#

A row of 3 cells with 3 colors and no equal neighbors has 12 colorings, in two patterns:

  • ABA: the ends match, e.g. red-yellow-red, 6 colorings.
  • ABC: all three differ, e.g. red-yellow-green, 6 colorings.

The next row must differ from the previous one in every cell. The number of compatible next rows depends only on the pattern (e.g. after ABA red-yellow-red, the next row can be yellow-red-yellow, green-red-green, yellow-green-yellow as ABA, and yellow-red-green, green-red-yellow as ABC):

new ABA = 3 × ABA + 2 × ABC
new ABC = 2 × ABA + 2 × ABC

My Attempts
#

Attempt 1 used dp[row][c1][c2][c3] directly, enumerating every valid coloring of each row against every valid coloring of the previous row, O(n · 27 · 27), which passed in 1.3 seconds.

Grouping the 12 colorings into two patterns leaves only 4 coefficients, O(n).

Solution
#

class Solution:
    def numOfWays(self, n: int) -> int:
        MOD = 10 ** 9 + 7
        aba = abc = 6
        for _ in range(n - 1):
            aba, abc = (3 * aba + 2 * abc) % MOD, (2 * aba + 2 * abc) % MOD
        return (aba + abc) % MOD

Complexity
#

Time O(n), space O(1).

Mistakes to Avoid
#

  • Check the coefficients by listing them by hand once (or with a brute force like attempt 1) rather than guessing.

Interview Explanation
#

A row’s 12 colorings fall into two patterns: ABA with matching ends and ABC with all different colors, 6 each. How many next rows fit depends only on the pattern: ABA allows 3 ABA and 2 ABC, ABC allows 2 ABA and 2 ABC. Pushing those two counts down row by row gives O(n).

Related

LeetCode 123: Best Time to Buy and Sell Stock III
·4 mins
LeetCode Hard Dynamic-Programming State-Machine
LeetCode note for Best Time to Buy and Sell Stock III, rebuilt from the original learning note
LeetCode 188: Best Time to Buy and Sell Stock IV
·4 mins
LeetCode Hard Dynamic-Programming State-Machine
LeetCode note for Best Time to Buy and Sell Stock IV, rebuilt from the original learning note
LeetCode 1335: Minimum Difficulty of a Job Schedule
·2 mins
LeetCode Hard Dynamic-Programming Interval-Dp Array
LeetCode 1335 note: partition DP into d segments; dp(i, k) = the least difficulty starting at job i with k days left, enumerating where today ends while updating today’s maximum
LeetCode 1745: Palindrome Partitioning IV
·2 mins
LeetCode Hard Dynamic-Programming Interval-Dp String
LeetCode 1745 note: build is_pal[i][j] with interval DP, then try both cut points; three palindromic parts means true, O(n^2)
LeetCode 312: Burst Balloons
·2 mins
LeetCode Hard Dynamic-Programming Interval-Dp Array
LeetCode 312 note: choose the last balloon k burst in the range (i, j); at that moment its neighbors are i and j, and the two sides are independent subproblems
LeetCode 3906: Count Good Integers on a Grid Path
·2 mins
LeetCode Hard Dynamic-Programming Digit-Dp
LeetCode 3906 note: the range reaches 9 × 10^15, so no per-number checks; a digit DP carries both lower and upper tight flags, plus the previous digit on the path since path cells must be non-decreasing