Skip to content

圆环回原点问题

约 770 字大约 3 分钟

2025-03-01

圆环上有10个点,编号为0~9。从0点出发,每次可以逆时针和顺时针走一步,问走n步回到0点共有多少种走法。

输入: 2
输出: 2
解释:有2种方案。分别是0->1->0和0->9->0

动态规划

dp[i][j] 表示从0出发,走 i 步到 j 的方案数。

走n步到0的方案数 = 走n-1步到1的方案数 + 走n-1步到9的方案数。

状态转移公式要取余,因为j-1或j+1可能会超过圆环0~9的范围

public class Solution {
    public int backToOrigin(int n) {
        // 点的个数为10
        int length = 10;
        // 创建二维数组dp。dp[i][j] 表示从0出发,走 i 步到 j 的方案数。
        int[][] dp = new int[n + 1][length];
        // dp[0][0] 表示从0出发,走0步到0的方案数为1,dp[0][j]为默认值0
        dp[0][0] = 1;

        // 遍历步数,从1到n
        for (int i = 1; i <= n; i++) {
            // 遍历点的位置,从0到length-1
            for (int j = 0; j < length; j++) {
                // j-1有可能为负,所以要加length把它变正,再取余。j+1加不加length都一样。
                dp[i][j] = dp[i - 1][(j - 1 + length) % length] + dp[i - 1][(j + 1) % length];
            }
        }

        // 返回dp[n][0],即走n步回到0的方案数
        return dp[n][0];
    }
}

滚动更新

public class Solution {

    public int backToOrigin(int n) {
        // 点的个数为10
        int length = 10;
        // 使用一维数组 dp 存储当前步数的方案数
        int[] dp = new int[length];
        dp[0] = 1; // 第一行的 dp[0] 表示从0出发,走0步到0的方案数为1,第n行的dp[0]表示从0出发,走n步到0的方案数。
        // 临时数组 temp 用于存储更新后的方案数
        int[] temp = new int[length];

        // 遍历步数,从1到n。temp指向本轮数组,dp是上一轮数组,计算完dp前进一步,即前进到temp。
        for (int i = 1; i <= n; i++) {
            // 每次步数更新时,将 temp 数组初始化为 0
            Arrays.fill(temp, 0);
            // 遍历点的位置,从0到length-1
            for (int j = 0; j < length; j++) {
                // temp[j] 表示从0出发,走i步到j的方案数
                // temp[j] = dp[(j-1+length)%length] + dp[(j+1)%length]
                // 为了保证dp[k]都是上一轮的值,我们这里不能直接更新dp数组,要先用临时数组保存。
                temp[j] = dp[(j - 1 + length) % length] + dp[(j + 1) % length];
            }

            // 将 temp 数组赋值给 dp 数组,以进行下一次步数的更新
            System.arraycopy(temp, 0, dp, 0, length);
        }

        // 返回 dp[0],即走 n 步回到 0 的方案数
        return dp[0];
    }
}

System.arraycopy 是标准且高效的选择,特别是在需要频繁复制大量数据的场景中。它是 Java 中处理数组复制的惯用方法之一,尤其是在涉及到性能敏感的应用时。

Arrays.copyOf 更适合需要返回一个新数组的情况,而 System.arraycopy 则适用于对现有数组的部分或全部内容进行复制。