一、题目解析
在这道题目中,我们面对的是一个包含数字的数组。每个数组元素被视为一个字符串,我们可以从每个字符串中选出一个字符组成一个新数。目标是使最终得到的数字的各个位之和为偶数,并且统计所有满足此条件的组合个数。
题目的关键点在于:
- 将每个数字分解成单个字符(每一位)。
- 遍历每个数字的所有位数组合,找出满足位数和为偶数的组合数量。
- 使用递归(回溯)来枚举所有可能的组合。
二、解题思路
- 分解问题:首先,将每个整数视为一个字符串,以便逐位访问每一个数字。这样可以灵活地从每一位数中选出一个数字。
- 递归回溯:利用递归逐步构建每一位的组合。通过递归的
backTrack函数,逐步从每一个数字中选取一个位数,并在最终判断构成的组合是否满足条件(位数和为偶数)。 - 判断条件:在组合完成后(递归到数组末尾),检查组合的各位和是否为偶数,如果是,则计数器加一。
- 清理全局状态:由于
result和path是全局变量,每次递归结束后需要清理这些变量的状态,以便适应多次调用。 三、代码详解 import java.util.*;
public class Main { static int result = 0; static ArrayList path = new ArrayList();
public static int solution(int[] numbers) {
// 调用回溯方法
backTrack(numbers, 0);
int r = result; // 记录当前结果
result = 0; // 清空结果,方便下次调用
path.clear(); // 清空路径
return r;
}
// 回溯方法
public static void backTrack(int[] numbers, int index) {
// 递归出口:当index达到数组长度
if (index == numbers.length) {
if (valid(path)) { // 检查是否满足条件
result++; // 满足条件则计数器加一
return;
} else {
return;
}
}
// 当前数字的每一位都作为单独的选择
String str = String.valueOf(numbers[index]);
for (int i = 0; i < str.length(); i++) {
char c = str.charAt(i);
path.add(Character.getNumericValue(c)); // 将字符转为数字并加入路径
backTrack(numbers, index + 1); // 递归下一个数字
path.remove(path.size() - 1); // 回溯:移除当前选择
}
}
// 检查路径是否满足条件(和为偶数)
public static boolean valid(ArrayList<Integer> arr) {
int sum = 0;
for (int i = 0; i < arr.size(); i++) {
sum += arr.get(i);
}
return sum % 2 == 0; // 返回是否为偶数
}
public static void main(String[] args) {
// 测试用例
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);
}
}
四、代码分析
-
全局变量:
result:记录符合条件的组合数。path:存储当前递归路径,用于组合各个位数。
-
主函数
solution(int[] numbers):- 负责调用
backTrack递归方法进行组合计算,并返回最终的result值。 - 每次调用
solution后,result和path会被重置,以便为下一次调用提供干净的环境。
- 负责调用
-
回溯函数
backTrack(int[] numbers, int index):- 该方法通过递归逐步访问每一个数字的每一位,从每个数字中选择一位加入
path。 - 递归结束时,通过
valid方法判断组合是否符合要求。 path.remove(path.size() - 1)是回溯的关键步骤,确保在每层递归结束时清理当前选择。
- 该方法通过递归逐步访问每一个数字的每一位,从每个数字中选择一位加入
-
有效性检查函数
valid(ArrayList<Integer> arr):- 计算
path中数字的和,判断是否为偶数。
- 计算
五、示例分析
以输入 [123, 456, 789] 为例:
123可以提供1,2,3三个选择。456提供4,5,6。789提供7,8,9。
通过回溯方法,可以生成 333 = 27 种组合,经过 valid 方法筛选,最终符合条件的组合数量为 14。
六、心得体会
- 回溯的灵活性:通过回溯可以轻松地生成所有可能的组合,这对题目中的数字组合问题非常适用。
- 全局状态清理:由于
result和path是全局变量,设计时需要在每次计算结束后清空状态,以防影响下一次调用。 - 问题分解:将问题分解成单个数字的组合,再用递归实现,简化了整体逻辑,使得代码更具条理性和扩展性。
七、改进方向
- 该算法使用全局变量存储结果,在多线程或并发环境中可能会产生不一致的问题。可以考虑将
result和path改为局部变量,并使用函数返回值传递结果,以提高代码的可重用性和稳定性。 - 此外,对于更大的数据集,算法的时间复杂度会迅速上升。可以引入动态规划或剪枝优化,提前排除不可能符合条件的组合,减少递归深度。