递归实现mySplit函数:整数数组分组判断需求与优化问询
另一种递归实现mySplit的思路
嘿,我来给你分享一个更清晰的递归实现思路,完全贴合你提出的四个规则,而且把核心逻辑都放在递归辅助函数里,mySplit只做前置处理和返回结果~
先理清楚问题的核心转化
首先我们可以把数组里的元素分成三类,提前处理规则3和规则4:
- 5的倍数:必须全部在同一组(我们默认放到第一组,不影响结果,因为只要两组总和相等就行),先计算它们的总和
sum5 - 3的倍数(非5的倍数):必须全部在第二组,计算它们的总和
sum3 - 自由数:既不是3也不是5的倍数的数,这些可以自由分配到两组中的任意一组,我们把它们收集到列表里,计算总和
sumFree
接下来推导两组总和相等的条件:
设第一组的总和 = sum5 + x(x是自由数中分到第一组的和)
第二组的总和 = sum3 + (sumFree - x)
要让两组相等,必须满足:sum5 + x = sum3 + sumFree - x
整理后得到:2x = sum3 + sumFree - sum5
这意味着:
sum3 + sumFree - sum5必须是非负偶数,否则x不是非负整数,不可能实现- 我们需要从自由数中选出一个子集,使得它们的和等于
(sum3 + sumFree - sum5) / 2——这就是递归要解决的子集和问题!
具体代码实现
public class SplitArray { public static boolean mySplit(int[] nums) { int sum5 = 0; int sum3 = 0; int sumFree = 0; // 收集自由数的列表,方便后续递归处理 java.util.List<Integer> freeList = new java.util.ArrayList<>(); for (int num : nums) { if (num % 5 == 0) { sum5 += num; } else if (num % 3 == 0) { sum3 += num; } else { freeList.add(num); sumFree += num; } } // 计算目标值:需要从自由数中凑出的和 int target = sum3 + sumFree - sum5; // 目标必须是非负偶数,否则直接返回false if (target < 0 || target % 2 != 0) { return false; } target /= 2; // 调用递归辅助函数,判断是否能凑出目标和 return canReachTarget(freeList, 0, 0, target); } // 递归辅助函数:判断从index开始的自由数能否凑出target // 参数:自由数列表、当前处理的索引、当前累加的和、目标和 private static boolean canReachTarget(java.util.List<Integer> freeList, int index, int currentSum, int target) { // 终止条件1:当前和等于目标,找到可行方案 if (currentSum == target) { return true; } // 终止条件2:遍历完所有数还没凑到目标,返回false if (index >= freeList.size()) { return false; } // 递归两种选择:选当前数,或者不选当前数 int currentNum = freeList.get(index); // 选当前数:当前和加上这个数,索引+1 boolean choose = canReachTarget(freeList, index + 1, currentSum + currentNum, target); // 不选当前数:当前和不变,索引+1 boolean notChoose = canReachTarget(freeList, index + 1, currentSum, target); // 只要其中一种选择可行,就返回true return choose || notChoose; } // 测试示例 public static void main(String[] args) { System.out.println(mySplit(new int[]{1, 1})); // true System.out.println(mySplit(new int[]{1, 1, 1})); // false System.out.println(mySplit(new int[]{2, 4, 2})); // true System.out.println(mySplit(new int[]{5, 21, 8, 15, 7})); // true System.out.println(mySplit(new int[]{15, 10, 5})); // false System.out.println(mySplit(new int[]{15, 8, 7})); // true } }
思路解释
- 前置处理:把数组元素按规则分类,提前计算固定组的总和,把可变部分提取出来,简化递归的问题规模
- 递归逻辑:对于每个自由数,我们有两种决策——加入第一组或者不加入,递归遍历所有可能的组合,只要找到一种组合能凑出目标和,就返回true
- 终止条件:要么找到符合条件的组合,要么遍历完所有数都找不到,终止递归
这种思路把复杂的分组问题转化为经典的子集和递归问题,逻辑清晰,也完全符合你要求的“所有逻辑在递归函数中实现,mySplit仅返回布尔值”的要求。
内容的提问来源于stack exchange,提问作者simon francis
相关产品推荐
相关产品推荐

