数字分组求偶数和 | 豆包MarsCode AI刷题

67 阅读4分钟

题解:计算各位数字之和为偶数的方案数

题目描述

给定一组数字(从1到9组成的数字串),这些数字被分成多个小组。从每个小组中选择一个数字,组成一个新的数,目标是使得这个新数的各位数字之和为偶数。需要计算有多少种分组和选择方法可以满足这一条件。

解题思路

我们可以利用 动态规划 解决这个问题。核心思路是通过动态转移的方式,统计从每个数字组中选择数字后,数字之和为偶数或奇数的所有可能方案数。


关键点解析

  1. 奇偶性判断

    • 一个数的各位数字之和为偶数,当且仅当其数字之和对2取模为0。
    • 从每个小组中选择一个数字时,可以记录奇数和偶数的数量,来更新当前选择的奇偶性。
  2. 动态规划

    • dp[0] 表示当前选择的数字之和为偶数的方案数,dp[1] 表示当前选择的数字之和为奇数的方案数。
    • 初始状态:dp = [1, 0],即还未选择任何数字时,数字之和为偶数的方案数为1(空集),数字之和为奇数的方案数为0。
  3. 状态转移

    • 对于每个数字组:
      • 如果选择一个偶数,和的奇偶性保持不变。
      • 如果选择一个奇数,和的奇偶性会翻转。
    • 假设当前数字组中有 even_count 个偶数,odd_count 个奇数,状态转移方程为:
      • dp_new[0] = dp[0] * even_count + dp[1] * odd_count
      • dp_new[1] = dp[1] * even_count + dp[0] * odd_count
    • 更新后,将 dp_new 的值赋给 dp,继续处理下一个数字组。
  4. 结果输出

    • 最终返回 dp[0],即所有方案中使得数字之和为偶数的数量。

算法实现

以下是完整代码:

def solution(numbers):
    # dp[0] 表示偶数和,dp[1] 表示奇数和
    dp = [1, 0]  # 初始状态,选择的数字和为0,显然是偶数

    for group in numbers:
        # group 是整数,先转换为字符串,再迭代每个字符计算奇偶数
        group_str = str(group)
        odd_count = sum(1 for digit in group_str if int(digit) % 2 == 1)
        even_count = len(group_str) - odd_count

        # 更新 dp 数组
        dp_new = [0, 0]
        dp_new[0] = dp[0] * even_count + dp[1] * odd_count
        dp_new[1] = dp[1] * even_count + dp[0] * odd_count
        dp = dp_new

    return dp[0]  # 返回偶数和的数量

if __name__ == "__main__":
    # 测试用例
    print(solution([123, 456, 789]) == 14)
    print(solution([123456789]) == 4)
    print(solution([14329, 7568]) == 10)

测试用例分析

  1. 测试用例1

    • 输入:[123, 456, 789]
    • 分析:每组分别有奇数偶数可以选择,动态规划累计的偶数方案数为 14
    • 输出:14
  2. 测试用例2

    • 输入:[123456789]
    • 分析:只有一个数字组,共有4种选择可以使各位数字之和为偶数。
    • 输出:4
  3. 测试用例3

    • 输入:[14329, 7568]
    • 分析:第一个组中奇偶数分别为 32,第二个组分别为 22。最终符合条件的偶数和方案数为 10
    • 输出:10

时间复杂度分析

  1. 假设数字组的数量为 m,每个组中数字的平均长度为 n
    • 遍历所有数字组计算奇偶性,复杂度为 O(mn)O(m \cdot n)
    • 动态规划的转移操作为 O(m)O(m)
  2. 因此,总时间复杂度为 O(mn)O(m \cdot n)

空间复杂度分析

  • 使用了固定大小的 dp 数组,空间复杂度为 O(1)O(1)

总结

本题通过动态规划解决了跨组数字奇偶性累计的复杂问题,核心在于使用 dp 表示当前奇偶性方案数,设计合理的状态转移方程。代码简洁高效,适用于不同大小的输入。


Java 代码

public class Solution {
    public static int countEvenSumNumbers(int[] numbers) {
        // dp[0] 表示偶数和方案数,dp[1] 表示奇数和方案数
        int[] dp = {1, 0}; // 初始状态

        for (int group : numbers) {
            // 将当前数字组转换为字符串
            String groupStr = String.valueOf(group);
            int oddCount = 0;
            int evenCount = 0;

            // 统计奇数和偶数的数量
            for (char digit : groupStr.toCharArray()) {
                if ((digit - '0') % 2 == 1) { // 判断是否为奇数
                    oddCount++;
                } else { // 偶数
                    evenCount++;
                }
            }

            // 更新 dp 数组
            int[] dpNew = new int[2];
            dpNew[0] = dp[0] * evenCount + dp[1] * oddCount; // 和为偶数的方案
            dpNew[1] = dp[1] * evenCount + dp[0] * oddCount; // 和为奇数的方案
            dp = dpNew;
        }

        return dp[0]; // 返回最终和为偶数的方案数
    }

    public static void main(String[] args) {
        // 测试用例
        System.out.println(countEvenSumNumbers(new int[]{123, 456, 789}) == 14);
        System.out.println(countEvenSumNumbers(new int[]{123456789}) == 4);
        System.out.println(countEvenSumNumbers(new int[]{14329, 7568}) == 10);
    }
}