【题解】卡片翻面求和问题 | 豆包MarsCode AI刷题

36 阅读2分钟

题目分析

给定n张卡牌,每张卡牌有正面和背面两个数字,通过动态规划的方法计算从前n张卡牌中选择某些卡牌,使得这些卡牌数字之和模3余0的方案数。

  1. 初始化dp[0][0] = 1,表示前0张卡牌,和为0的方案数为1。

  2. 状态转移

    • 对于每一张卡牌,我们考虑选择正面或背面的情况。
    • 更新 dp 数组时,使用 (j + front) % 3 和 (j + back) % 3 来计算新的余数。
  3. 返回结果:最终返回 dp[n][0],即前 n 张卡牌中,和模3余0的方案数

解题思路

  1. 需要计算所有可能的组合,使得这些组合的数字之和可以被3整除。

  2. 使用一个二维数组 dp,其中 dp[i][j] 表示前 i 张卡牌中,选择某些卡牌使得它们的和模3余 j 的方案数。

  3. 对于每一张卡牌,我们可以选择它的正面或背面。 更新 dp 数组时,考虑当前卡牌的正面和背面数字对当前状态的影响。

java代码

public class Main {
public static int solution(int n, int[] a, int[] b) {
    int MOD = 1000000007;
    // dp[i][j] 表示前 i 张卡牌中,选择某些卡牌使得它们的和模3余 j 的方案数
    int[][] dp = new int[n + 1][3];
    
    // 初始化:前0张卡牌,和为0的方案数为1
    dp[0][0] = 1;
    
    // 遍历每一张卡牌
    for (int i = 1; i <= n; i++) {
        // 当前卡牌的正面和背面数字
        int front = a[i - 1];
        int back = b[i - 1];
        
        // 更新 dp 数组
        for (int j = 0; j < 3; j++) {
            // 选择正面的情况
            dp[i][(j + front) % 3] = (dp[i][(j + front) % 3] + dp[i - 1][j]) % MOD;
            // 选择背面的情况
            dp[i][(j + back) % 3] = (dp[i][(j + back) % 3] + dp[i - 1][j]) % MOD;
        }
    }
    
    // 返回前 n 张卡牌中,和模3余0的方案数
    return dp[n][0];
}

public static void main(String[] args) {
    System.out.println(solution(3, new int[]{1, 2, 3}, new int[]{2, 3, 2}) == 3);
    System.out.println(solution(4, new int[]{3, 1, 2, 4}, new int[]{1, 2, 3, 1}) == 6);
    System.out.println(solution(5, new int[]{1, 2, 3, 4, 5}, new int[]{1, 2, 3, 4, 5}) == 32);
}
}

算法思路

动态规划通过定义合适的状态dp[i][j],将问题分解为子问题,即从前i张卡牌中满足和模3余j的方案数由前i - 1张卡牌的状态推导而来。这种状态转移方式涵盖了所有可能的组合情况。

时间复杂度

代码中有两层嵌套的循环,外层循环遍历n次,内层循环每次遍历3次。所以总的时间复杂度为𝑂(𝑛×3)O(n×3),即𝑂(3𝑛)O(3n),简化后为𝑂(𝑛)O(n)。

空间复杂度

代码中定义了一个大小为(n + 1)×3的二维数组dp来存储动态规划的状态,所以空间复杂度为𝑂(𝑛)O(n)。