补充题2. 圆环回原点问题(Circle Return Origin)

频次 ★★★★ · 难度 🟡 · 高频:字节

题目

圆环上有 n 个点(编号 0 ~ n-1),从原点 0 出发,每次可以顺时针走一步或逆时针走一步。给定步数 k,求回到原点 0 的方案数。

示例

输入: n = 3, k = 2
输出: 2
解释: 0→1→0、0→2→0 两种

思路

二维 DPdp[i][j] 表示走 i 步到达 j 点的方案数。

转移:dp[i][j] = dp[i-1][(j-1+n)%n] + dp[i-1][(j+1)%n]

起点 dp[0][0] = 1,答案是 dp[k][0]

滚动数组优化空间:只保留两行。

代码

public int circleReturn(int n, int k) {
    int[][] dp = new int[k + 1][n];
    dp[0][0] = 1;
    for (int i = 1; i <= k; i++) {
        for (int j = 0; j < n; j++) {
            dp[i][j] = dp[i - 1][(j - 1 + n) % n]
                     + dp[i - 1][(j + 1) % n];
        }
    }
    return dp[k][0];
}

空间优化版(滚动数组):

public int circleReturn(int n, int k) {
    int[] dp = new int[n];
    dp[0] = 1;
    for (int i = 0; i < k; i++) {
        int[] next = new int[n];
        for (int j = 0; j < n; j++) {
            next[j] = dp[(j - 1 + n) % n] + dp[(j + 1) % n];
        }
        dp = next;
    }
    return dp[0];
}

复杂度

  • 时间:O(k × n)
  • 空间:O(n)(滚动数组)或 O(k × n)

边界条件

  • k = 0:已经在原点,只有 1 种方案(不走)
  • n = 1:只有 1 个点,走任何步都在原点,方案数 = 2
  • n = 2:两个点相对,走奇数步不可能回到原点

变式

  • 如果每步可走 m 种距离:内层加一层循环枚举所有步长
  • 70. 爬楼梯:一维版本
  • 二维平面网格回原点:从 (0,0) 出发上下左右走 k 步回原点的方案数,状态升为三维

易错点

  • 取模方向(j - 1 + n) % n 不要漏掉 + n,Java 里 -1 % n 会是负数
  • 步数维度在外层:必须外层循环步数,内层循环点,因为每步的状态依赖上一步
  • 滚动数组时 dp[j] 含义是上一步的 j:新行算完前不要覆盖旧行

面试追问

  • n = 3, k 很大的时候怎么优化? 递推是线性的,可以用矩阵快速幂将 O(k) 优化到 O(n³ log k),但面试中写 DP 即可
  • 和「机器人走方格」的区别? 本题是一维环状封闭道路,62 题是二维开放网格,本质都是计数 DP,区别在状态维度和边界条件

关联题