数字分组求偶数和
题目如下:
小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(因为后续的选择不会改变总和的奇偶性)。
代码解析
-
解析数字分组:
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)用于从低位到高位添加数字,确保数字的顺序正确。 -
回溯算法:
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);
}
}