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

85 阅读4分钟

问题描述

小M面对一组从 1 到 9 的数字,这些数字被分成多个小组,并从每个小组中选择一个数字组成一个新的数。目标是使得这个新数的各位数字之和为偶数。任务是计算出有多少种不同的分组和选择方法可以达到这一目标。

  • numbers: 一个由多个整数字符串组成的列表,每个字符串可以视为一个数字组。小M需要从每个数字组中选择一个数字。

例如对于[123, 456, 789],14个符合条件的数为:147 149 158 167 169 248 257 259 268 347 349 358 367 369

测试样例

样例1:

输入:numbers = [123, 456, 789]
输出:14

样例2:

输入:numbers = [123456789]
输出:4

样例3:

输入:numbers = [14329, 7568]
输出:10

背景介绍

这个问题来源于组合数学中的一个典型问题,它涉及了数字的分组和从每个组中选择一个数字来满足特定条件。在实际应用中,这类问题常常出现在数据分类、信号处理、编码理论、排列组合等领域。问题本身简单直观,但却能够通过不同的思维方式引发多种解法,且能够加深对数字性质、组合方式以及数学算法的理解。 在这个问题中,给定了一组数字,这些数字被分成了多个小组,目标是从每个小组中选择一个数字,组成一个新的数字,且该新数字的各位数字之和需要满足偶数的条件。偶数的特性之一是其各位数字之和为偶数,因此可以通过一些技巧性的方法来找到符合条件的解。

解题思路

  1. 理解题目和问题的条件: 我们的任务是从每个数字组中选择一个数字,组成一个新的数,使得这个新数的各位数字之和为偶数。由于偶数的定义是其数字和为偶数,因此可以通过判断数字和的奇偶性来得出结论。
  2. 如何判断新数的数字和的奇偶性: 对于新数字的各位数字之和,只有最后一位的奇偶性才是决定整个数和奇偶性的关键。因为其他位数的数字对总和奇偶性的影响是递进的,而最后一位数字直接决定了这个数的最终奇偶性。例如,如果最后一位数字为偶数,则总和为偶数;如果最后一位数字为奇数,则总和为奇数。
  3. 动态规划: 由于需要从每个小组中选择一个数字,问题的复杂度呈指数增长。为了避免重复计算,可以使用动态规划的方法。定义一个状态 dp[i][0] 表示前 i 组选择数字后,数字和为偶数的方案数;dp[i][1] 表示数字和为奇数的方案数。
    • 对于每个数字组中的每个数字,判断该数字的奇偶性,并根据它的奇偶性更新动态规划状态:
    • 如果当前数字是偶数,选择它不影响当前总和的奇偶性。
    • 如果当前数字是奇数,选择它会改变当前总和的奇偶性。
  4. 初始化和递推: 初始时,dp[0][0] = 1,即前 0 组(没有选择任何数字)时,数字和为偶数的方案数为 1;dp[0][1] = 0,即没有选择任何数字时,数字和不可能为奇数。对于每一组数字,根据数字的奇偶性,更新 dp[i][0]dp[i][1],直到处理完所有数字组。
  5. 结果计算: 最终,我们需要返回 dp[n][0],即所有数字组中选择一个数字后的结果,且数字和为偶数的方案数。

代码参考

def count_even_sum_numbers(numbers):
    # dp[i][0] 表示前 i 组选择数字后,和为偶数的方案数
    # dp[i][1] 表示前 i 组选择数字后,和为奇数的方案数
    dp = [[0, 0] for _ in range(len(numbers) + 1)]
    dp[0][0] = 1  # 没有选数字时和为偶数
    for i in range(1, len(numbers) + 1):
        group = numbers[i - 1]
        even_count, odd_count = 0, 0
        for digit in group:
            if int(digit) % 2 == 0:
                even_count += 1
            else:
                odd_count += 1
        dp[i][0] = dp[i - 1][0] * even_count + dp[i - 1][1] * odd_count
        dp[i][1] = dp[i - 1][0] * odd_count + dp[i - 1][1] * even_count
    return dp[len(numbers)][0]  # 返回和为偶数的方案数