1931. 用三种不同颜色为网格涂色

题目链接

1931. 用三种不同颜色为网格涂色 - 力扣(LeetCode)

题目描述

给你两个整数 m 和 n 。构造一个 m x n 的网格,其中每个单元格最开始是白色。请你用 红、绿、蓝 三种颜色为每个单元格涂色。所有单元格都需要被涂色。

涂色方案需要满足:不存在相邻两个单元格颜色相同的情况 。返回网格涂色的方法数。因为答案可能非常大, 返回 对 109 + 7 取余 的结果。

题目示例

示例 1 :

plain 复制代码
输入:m = 1, n = 1
输出:3
解释:如上图所示,存在三种可能的涂色方案。

示例 2 :

plain 复制代码
输入:m = 1, n = 2
输出:6
解释:如上图所示,存在六种可能的涂色方案。

解题思路

  1. 问题理解 :
    • 给定一个m x n的网格,用3种颜色涂色,要求相邻网格颜色不同。
    • 计算所有合法的涂色方案数,结果对10^9+7取模。
  2. 关键思路 :
    • 状态压缩:将每列的颜色状态用三进制数表示(0/1/2对应三种颜色)。
    • 有效状态筛选:生成所有列内相邻颜色不同的有效状态。
    • 状态转移图:构建状态之间的转移关系(相邻列对应位置颜色不同)。
    • 记忆化搜索:动态规划计算方案数,避免重复计算。
  3. 算法流程 :
    • 预处理3的幂次数组pow3,用于状态处理。
    • 生成所有有效的列颜色状态valid。
    • 构建状态转移图nxt,表示每个状态可以转移到哪些其他状态。
    • 使用记忆化搜索dfs计算方案数,从最后一列开始递归。
    • 汇总所有可能的初始状态的方案数,返回结果。

题解代码

java 复制代码
class Solution {
    private static final int MOD = 1_000_000_007; // 模数,防止结果溢出

    public int colorTheGrid(int m, int n) {
        // 计算3的幂次数组,用于后续处理颜色状态
        int[] pow3 = new int[m];
        pow3[0] = 1;
        for (int i = 1; i < m; i++) {
            pow3[i] = pow3[i - 1] * 3;
        }

        // 生成所有有效的列颜色状态(相邻颜色不同)
        List<Integer> valid = new ArrayList<>();
        next:
        for (int color = 0; color < pow3[m - 1] * 3; color++) {
            for (int i = 1; i < m; i++) {
                // 检查相邻颜色是否相同
                if (color / pow3[i] % 3 == color / pow3[i - 1] % 3) {
                    continue next; // 相同则跳过
                }
            }
            valid.add(color); // 有效状态加入列表
        }

        // 构建状态转移图:每个有效状态可以转移到哪些其他有效状态
        int nv = valid.size();
        List<Integer>[] nxt = new ArrayList[nv];
        Arrays.setAll(nxt, i -> new ArrayList<>());
        for (int i = 0; i < nv; i++) {
            next2:
            for (int j = 0; j < nv; j++) {
                for (int p3 : pow3) {
                    // 检查对应位置颜色是否相同
                    if (valid.get(i) / p3 % 3 == valid.get(j) / p3 % 3) {
                        continue next2; // 相同则跳过
                    }
                }
                nxt[i].add(j); // 可以转移的状态
            }
        }

        // 记忆化数组,memo[i][j]表示第i列使用状态j时的方案数
        int[][] memo = new int[n][nv];
        for (int[] row : memo) {
            Arrays.fill(row, -1);
        }

        // 计算所有可能的初始状态的总方案数
        long ans = 0;
        for (int j = 0; j < nv; j++) {
            ans += dfs(n - 1, j, nxt, memo);
        }
        return (int) (ans % MOD);
    }

    // 记忆化搜索
    private int dfs(int i, int j, List<Integer>[] nxt, int[][] memo) {
        if (i == 0) {
            return 1; // 基础情况:第一列
        }
        if (memo[i][j] != -1) {
            return memo[i][j]; // 已计算过
        }
        long res = 0;
        // 遍历所有可能的下一个状态
        for (int k : nxt[j]) {
            res += dfs(i - 1, k, nxt, memo);
        }
        return memo[i][j] = (int) (res % MOD); // 存储并返回结果
    }
}

复杂度分析

  1. 时间复杂度 :
    • 生成有效状态:O(m * 3^m)
    • 构建状态转移图:O(m * 3^(2m))
    • 记忆化搜索:O(n * 3^m)
    • 总体:O(n * 3^m + m * 3^(2m)),当m较小时可行
  2. 空间复杂度 :
    • 存储状态转移图:O(3^(2m))
    • 记忆化数组:O(n * 3^m)
    • 总体:O(n * 3^m + 3^(2m))
相关推荐
乐迪信息2 小时前
港口船舶逆行怎么管?AI防爆摄像机搭载智能检测算法
大数据·人工智能·深度学习·算法·计算机视觉
Sirens.3 小时前
Java并发锁详解:六类锁策略与 synchronized 底层原理
java·前端·算法
和裕4 小时前
全纸结构重型纸箱能否满足 1 吨以上设备出口熏蒸豁免要求?通关合规性全解析
大数据·运维·网络·人工智能·算法
tangguofeng4 小时前
不带头结点的链队操作集(不含InitFlag)(C语言版)
算法
苏打豆5 小时前
CRISP源码阅读——基于ROS2力矩反馈控制器与速度加速度零空间
c++·线性代数·算法·矩阵·机器人
蛋蛋的就会顺顺的6 小时前
hot100——矩阵
java·数据结构·算法·leetcode·力扣
老歌老听老掉牙6 小时前
麻花钻切屑形态演变的力学机制与临界条件分析
python·算法·钻头
zhangfeng11337 小时前
国产GPU/AI算力芯片现状(修订完整版 · 截至2026年9月
人工智能·算法·ai编程·npu
学代码的CJY7 小时前
从代码出发理解时间复杂度与空间复杂度
数据结构·算法
白帽攻防录7 小时前
SRC 挖洞:WSO2 JWT 算法混淆绕过深度复盘,CVE-2026-5430 不支持的算法怎么变成管理员
网络·算法·安全·网络安全·jwt