AI刷题 426 拨号器 | 豆包MarsCode AI刷题

85 阅读4分钟

学习方法与心得:解析骑士拨号问题

一、题目解析与解决思路

题目背景

“骑士拨号问题”是一道与图遍历和动态规划相关的经典题目。题目描述了一名骑士在一个 3x4 的键盘上按照国际象棋中的“马”跳跃规则,拨打电话号码的过程。目标是计算骑士在给定跳跃次数下,可以拨打的不同电话号码数量。

这一问题看似简单,但背后涉及路径规划、图的遍历和优化算法,是学习动态规划的重要案例。

解题思路

1. 问题建模

骑士的跳跃可以看成一个图的遍历问题,每个数字是图中的一个节点,跳跃规则决定了节点之间的边。例如,数字 1 可以跳到 68,对应的是从 168 的边。

2. 动态规划思想

我们可以利用动态规划的状态转移思想来解决:

  • 定义状态 dp[k][i] 表示以数字 i 结尾的、长度为 k 的电话号码数量。
  • 初始状态:dp[1][i] = 1(长度为 1 时,每个数字都可以作为单独的电话号码)。
  • 状态转移:长度为 k 的号码可以通过长度为 k-1 的号码延伸而来。具体公式为: [ dp[k][i] = \sum_{j \in moves[i]} dp[k-1][j] ] 其中 moves[i] 是从数字 i 出发可以跳到的所有数字集合。
3. 模运算处理大数

由于结果可能非常大,我们需要对 (10^9 + 7) 取模,保证计算不会溢出。

具体代码

public static int solution(int n) {
    // 定义跳跃规则
    int[][] moves = {
        {4, 6},     // 0
        {6, 8},     // 1
        {7, 9},     // 2
        {4, 8},     // 3
        {0, 3, 9},  // 4
        {},         // 5 (不可到达)
        {0, 1, 7},  // 6
        {2, 6},     // 7
        {1, 3},     // 8
        {2, 4}      // 9
    };

    int MOD = 1_000_000_007; // 模数
    int[][] dp = new int[n + 1][10]; // 动态规划数组

    // 初始化:长度为1的情况
    for (int i = 0; i <= 9; i++) {
        dp[1][i] = 1;
    }

    // 动态规划递推
    for (int k = 2; k <= n; k++) {
        for (int i = 0; i <= 9; i++) {
            dp[k][i] = 0; // 初始化当前长度的值
            for (int move : moves[i]) {
                dp[k][i] = (dp[k][i] + dp[k - 1][move]) % MOD;
            }
        }
    }

    // 汇总结果
    int result = 0;
    for (int i = 0; i <= 9; i++) {
        result = (result + dp[n][i]) % MOD;
    }

    return result;
}

二、知识总结与学习心得

1. 图的遍历与建模

本题核心在于将数字键盘建模为一个图,每个数字是节点,跳跃规则决定了节点之间的连接关系。这种建模能力对解决更复杂的路径问题非常有帮助。

2. 动态规划的状态设计

在动态规划中,设计状态和状态转移是关键。通过状态 dp[k][i] 表达当前路径的局部解,避免重复计算,是动态规划的核心思想。

3. 大数取模的必要性

在类似的问题中,结果可能快速增长。提前考虑模运算,不仅可以防止溢出,还可以提高效率。


三、学习计划与高效刷题方法

1. 制定目标与计划

  • 目标分解:针对骑士拨号问题,我将动态规划问题分为入门(简单的线性问题)到高级(多状态问题)逐步攻克。
  • 时间规划:每天花 1 小时刷题,集中训练动态规划和图论两类问题。

2. 善用错题与总结

  • 错题整理:将自己出错的题目分类整理,例如是状态转移出错还是边界条件没处理好。
  • 知识点总结:通过刷题记录总结动态规划的模板和图遍历的常见技巧。

3. AI 工具结合学习

  • 代码调试:通过 MarsCode AI,快速发现代码问题并优化效率。
  • 知识拓展:利用 AI 提供的题解功能,学习多种解法并比较优劣。

四、学习建议

  • 理解题目是关键:不要急于动手写代码,先将题目抽象为模型,明确核心问题。
  • 动态规划要多练:状态设计、转移公式和边界条件处理是动态规划的重点。
  • 善用工具辅助:AI 刷题工具不仅能提供高质量题目,还能帮助理解解题思路。

通过坚持不懈地训练和总结,骑士拨号问题不仅帮助我提升了解题能力,更让我掌握了动态规划和图遍历的核心技能。