news 2026/10/27 5:19:44

LeetCode 1411:网格涂色问题的动态规划解法

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
LeetCode 1411:网格涂色问题的动态规划解法

1. 问题背景与理解

这道LeetCode题目(1411. 给Nx3网格图涂色的方案数)看似简单,却蕴含着不少有趣的组合数学思想。题目要求我们计算用三种颜色给N行3列的网格涂色的方案数,且相邻格子颜色不能相同。这里的"相邻"指的是上下左右四个方向的直接相邻。

我第一次看到这个问题时,以为就是个简单的排列组合题。但当我尝试用暴力枚举法解决时,很快就发现随着N的增加,计算量呈指数级增长。比如当N=5时,理论上有3^15种可能的涂法(每个格子3种选择,共15个格子),直接枚举显然不现实。

2. 基础解法分析

2.1 小规模情况枚举

让我们先从小规模的N开始分析。对于N=1的情况,即单行3列的网格:

  • 第一个格子有3种选择
  • 第二个格子有2种选择(不能与第一个相同)
  • 第三个格子有2种选择(不能与第二个相同)

所以总共有3×2×2=12种涂法。这与题目给出的示例一致。

但当N=2时,情况就复杂多了。第二行的涂法不仅取决于自身的相邻格子,还受第一行的影响。这时候我们就需要更系统的方法。

2.2 状态转移思路

这个问题非常适合用动态规划来解决。我们可以将每一行的涂色模式视为一个"状态",然后计算从一个状态转移到另一个状态的方案数。

具体来说,每一行的涂色模式可以分为两类:

  1. ABC型:三个格子颜色各不相同,如红绿蓝
  2. ABA型:两边的格子颜色相同,中间的格子颜色不同,如红绿红

对于N=1时:

  • ABC型有6种(3种颜色排列)
  • ABA型有6种(3种主色×2种中间色)

3. 动态规划解法实现

3.1 状态定义与转移方程

设:

  • dp_abc[n] 表示第n行是ABC型的方案数
  • dp_aba[n] 表示第n行是ABA型的方案数

初始条件:

  • dp_abc[1] = 6
  • dp_aba[1] = 6

转移方程:

  • 一个ABC型的下一行可以是:

    • 2种ABC型(如红绿蓝→绿红绿、绿蓝绿)
    • 2种ABA型(如红绿蓝→绿红蓝、绿蓝红)
  • 一个ABA型的下一行可以是:

    • 2种ABC型(如红绿红→绿红绿、绿蓝绿)
    • 3种ABA型(如红绿红→绿红绿、绿蓝绿、蓝绿蓝)

因此转移方程为: dp_abc[n] = 2 * dp_abc[n-1] + 2 * dp_aba[n-1] dp_aba[n] = 2 * dp_abc[n-1] + 3 * dp_aba[n-1]

3.2 Java实现代码

public int numOfWays(int n) { if (n == 0) return 0; long abc = 6; // ABC型 long aba = 6; // ABA型 long mod = 1000000007; for (int i = 2; i <= n; i++) { long new_abc = (2 * abc + 2 * aba) % mod; long new_aba = (2 * abc + 3 * aba) % mod; abc = new_abc; aba = new_aba; } return (int)((abc + aba) % mod); }

3.3 复杂度分析

  • 时间复杂度:O(N),因为我们只需要进行N次迭代计算
  • 空间复杂度:O(1),只使用了常数个变量存储状态

4. 数学优化与矩阵快速幂

4.1 状态转移的矩阵表示

我们可以将状态转移表示为矩阵乘法:

[abc_n] = [2 2][abc_{n-1}] [aba_n] [2 3][aba_{n-1}]

这意味着我们可以使用矩阵快速幂来将时间复杂度优化到O(logN)。

4.2 矩阵快速幂实现

final int MOD = 1000000007; public int numOfWays(int n) { if (n == 0) return 0; if (n == 1) return 12; long[][] transition = {{2, 2}, {2, 3}}; long[][] result = matrixPower(transition, n - 1); long abc = 6, aba = 6; long total = (result[0][0] * abc + result[0][1] * aba) % MOD; total = (total + (result[1][0] * abc + result[1][1] * aba) % MOD) % MOD; return (int)total; } private long[][] matrixPower(long[][] matrix, int power) { long[][] result = {{1, 0}, {0, 1}}; // 单位矩阵 while (power > 0) { if ((power & 1) == 1) { result = multiplyMatrix(result, matrix); } matrix = multiplyMatrix(matrix, matrix); power >>= 1; } return result; } private long[][] multiplyMatrix(long[][] a, long[][] b) { long[][] res = new long[2][2]; for (int i = 0; i < 2; i++) { for (int j = 0; j < 2; j++) { res[i][j] = (a[i][0] * b[0][j] + a[i][1] * b[1][j]) % MOD; } } return res; }

5. 边界条件与注意事项

5.1 大数处理

由于结果可能非常大(当N=5000时,结果约为1e2000量级),题目要求对结果取模1000000007。在实现时需要注意:

  1. 使用long类型存储中间结果,避免int溢出
  2. 每次运算后立即取模,而不是最后才取模
  3. 矩阵乘法中的乘法操作可能导致中间结果溢出,需要及时取模

5.2 初始条件

当N=0时,应该返回0,因为没有格子需要涂色。这是一个容易被忽略的边界条件。

5.3 测试用例验证

建议测试以下情况:

  • N=1 → 12
  • N=2 → 54
  • N=3 → 246
  • N=7 → 106494
  • N=5000 → 30228214

6. 扩展思考

6.1 更一般的m×n网格

如果问题扩展到m×n网格(m不固定为3),解法会有什么变化?

这种情况下,状态数会随着m的增加而急剧增加(对于m列,状态数约为3×2^(m-1))。对于较大的m,可能需要更复杂的动态规划方法或状态压缩技巧。

6.2 颜色数量的变化

如果题目改为使用k种颜色而不是3种,解法需要如何调整?

初始的ABC型和ABA型的数量会变化:

  • ABC型:k×(k-1)×(k-2)
  • ABA型:k×(k-1)

转移方程中的系数也需要相应调整。

6.3 实际应用场景

这类问题在实际中有多种应用:

  1. 平面地图着色问题
  2. 电路板布线设计
  3. 日程安排中的冲突避免
  4. 图形学中的纹理生成

7. 个人解题心得

在解决这个问题时,我最初尝试了暴力回溯法,很快就遇到了性能瓶颈。通过分析小规模案例,我发现了状态分类的规律。动态规划的解法虽然高效,但推导状态转移方程需要仔细分析所有可能的情况。

矩阵快速幂的优化是一个惊喜,它将线性时间复杂度降低到了对数级。这提醒我在解决类似问题时,可以考虑是否存在数学上的优化空间。

一个容易犯的错误是忽略了模运算的时机。我在第一次提交时,只在最后做了取模,结果中间计算就溢出了。正确的做法是在每次运算后都立即取模。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/27 5:19:40

P2P NAT穿越实战:STUN/TURN/ICE打洞原理与排障指南

1. 这不是“黑科技”&#xff0c;而是每个真实P2P系统绕不开的生存课你写完一个点对点文件共享程序&#xff0c;本地测试一切正常——两台电脑在同一个Wi-Fi下传文件快得飞起&#xff1b;你信心满满地把服务端部署到云服务器&#xff0c;让朋友从家里连进来试试&#xff0c;结果…

作者头像 李华
网站建设 2026/10/27 5:19:40

eNSP新手入门:从命令行第一行到网络排错黄金三角

1. 这不是模拟器教学&#xff0c;是网络工程师的“第一次呼吸”你打开eNSP&#xff0c;界面左上角那个蓝色图标像不像刚拆封的路由器包装盒&#xff1f;我第一次点开它时也以为只是个图形化玩具——直到在某高校实验室带学生做课设&#xff0c;一个大二同学用eNSP搭出三层交换O…

作者头像 李华
网站建设 2026/10/27 5:19:31

OpenMontage:面向AI视频生产的声明式代理流水线

1. OpenMontage不是又一个视频剪辑软件&#xff0c;而是一套“可编程的影像流水线”OpenMontage这个名字乍听像某个复古胶片播放器&#xff0c;或者某款小众开源剪辑工具——我最初也这么以为。直到在GitHub上点开它的仓库首页&#xff0c;看到第一行README写着&#xff1a;“A…

作者头像 李华
网站建设 2026/10/27 5:18:23

AI 提示注入攻击是什么?为什么不能完全信任模型读到的内容?

AI 提示注入攻击是什么&#xff1f;为什么不能完全信任模型读到的内容&#xff1f; AI 应用不仅会接收用户直接输入的指令&#xff0c;还可能读取网页、邮件、文档和知识库内容。如果这些外部内容包含刻意设计的指令&#xff0c;模型就可能被诱导偏离原本的任务。 这种风险通常…

作者头像 李华
网站建设 2026/10/27 5:17:57

B2B企业海外AI获客评估:AI推荐、内容与合规怎么选

海外AI搜索的变化&#xff0c;让外贸企业开始重新审视内容、信源和官网承接之间的关系。 2026年&#xff0c;外贸行业最大的变化之一&#xff0c;不是平台数量&#xff0c;而是AI搜索开始成为新的获客入口。 行业快速升温也带来服务质量分化&#xff0c;有些团队只是把传统SEO换…

作者头像 李华
网站建设 2026/10/27 5:17:38

text-to-cad:从自然语言到参数化CAD模型的工程落地实践

先把话说在前面&#xff1a;这两年“用嘴建模”从一个玩笑话&#xff0c;逐渐变成了能落地的工程工具。text-to-cad&#xff08;文本生成CAD模型&#xff09;这个词&#xff0c;我最早看到是在一些AI辅助设计的开源项目里&#xff0c;当时觉得也就是自动生成个示意图&#xff0…

作者头像 李华