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

76 阅读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 到 9 之间选择,因此每个数字的奇偶性是已知的。我们可以利用这一点来简化问题。

  1. 奇偶性分析

    • 偶数 + 偶数 = 偶数
    • 偶数 + 奇数 = 奇数
    • 奇数 + 奇数 = 偶数
  2. 回溯算法

    • 使用回溯算法可以有效地枚举所有可能的选择组合。
    • 从第一个分组开始,尝试选择其中的每一个数字,并递归地处理下一个分组。
    • 在每一步递归中,记录当前选择的数字之和,并在处理完所有分组后检查总和是否为偶数。
  3. 优化

    • 为了提高效率,可以在递归过程中提前剪枝,避免不必要的计算。
    • 例如,如果当前的和已经是偶数且剩余的分组中没有奇数,那么可以直接返回 1(因为后续的选择不会改变总和的奇偶性)。

代码解析

  1. 解析数字分组

    List<List<Integer>> groups = new ArrayList<>();
    for (int number : numbers) {
        List<Integer> digits = new ArrayList<>();
        while (number > 0) {
            digits.add(0, number % 10);  // 从低位到高位添加
            number /= 10;
        }
        groups.add(digits);
    }
    

    这段代码将每个输入的整数解析成单个数字,并存储在一个嵌套的列表中。digits.add(0, number % 10) 用于从低位到高位添加数字,确保数字的顺序正确。

  2. 回溯算法

    private static int backtrack(int index, int currentSum, List<List<Integer>> groups) {
        if (index == groups.size()) {
            // 如果已经处理完所有的分组,检查总和是否为偶数
            return (currentSum % 2 == 0) ? 1 : 0;
        }
    
        int count = 0;
        for (int num : groups.get(index)) {
            // 对于当前分组中的每个数字,递归地处理下一个分组
            count += backtrack(index + 1, currentSum + num, groups);
        }
        return count;
    }
    
    • if (index == groups.size()):如果已经处理完所有的分组,检查当前的总和是否为偶数。如果是偶数,返回 1;否则返回 0。
    • for (int num : groups.get(index)):遍历当前分组中的每一个数字。
    • count += backtrack(index + 1, currentSum + num, groups):递归地处理下一个分组,并累加满足条件的组合数。

代码解答

import java.util.ArrayList;
import java.util.List;

public class Main {
    /**
     * 计算满足条件(新组成的数字每位数字相加之和为偶数)的组合数。
     *
     * @param numbers 输入的整数数组,每个整数代表一组数字
     * @return 满足条件的组合数
     */
    public static int solution(int[] numbers) {
        // 将每个整数解析成单个数字,并存储在列表中
        List<List<Integer>> groups = new ArrayList<>();
        for (int number : numbers) {
            List<Integer> digits = new ArrayList<>();
            while (number > 0) {
                digits.add(0, number % 10);  // 从低位到高位添加
                number /= 10;
            }
            groups.add(digits);
        }

        // 开始回溯算法
        return backtrack(0, 0, groups);
    }

    /**
     * 回溯算法,尝试从每一组中选择一个数字,并跟踪当前构建的数字的各位数字之和。
     *
     * @param index 当前处理的分组索引
     * @param currentSum 当前构建的数字的各位数字之和
     * @param groups 解析后的整数列表的列表
     * @return 从当前分组开始的满足条件的组合数
     */
    private static int backtrack(int index, int currentSum, List<List<Integer>> groups) {
        if (index == groups.size()) {
            // 如果已经处理完所有的分组,检查总和是否为偶数
            return (currentSum % 2 == 0) ? 1 : 0;
        }

        int count = 0;
        for (int num : groups.get(index)) {
            // 对于当前分组中的每个数字,递归地处理下一个分组
            count += backtrack(index + 1, currentSum + num, groups);
        }
        return count;
    }

    public static void main(String[] args) {
        // You can add more test cases here
        System.out.println(solution(new int[]{123, 456, 789}) == 14);
        System.out.println(solution(new int[]{123456789}) == 4);
        System.out.println(solution(new int[]{14329, 7568}) == 10);
    }
}