基于递归实现数组近似平衡划分的C语言技术咨询
近似平衡数组划分的递归C语言实现
递归辅助函数设计思路
递归核心是逐个处理数组元素,每一步对当前元素做两种选择:放入第一组或第二组。需要跟踪以下关键状态:
- 当前处理的数组索引
- 两组各自的元素和
- 两组各自的元素数量
- 标记数组(记录每个元素归属的组,用于后续输出)
- 找到有效划分的标志(避免不必要的递归)
递归终止条件:
- 处理完所有元素(索引等于数组大小):检查两组和是否相等,且元素数量差≤2。如果满足,标记找到解并返回;否则回溯。
- 已经找到有效划分:直接返回,不再继续递归。
完整实现代码
#include <stdio.h> #include <stdlib.h> #include <stdlib.h> // 全局标志:标记是否找到符合条件的划分 int found = 0; // 递归辅助函数:处理当前索引的元素,尝试放入两组之一 void helper(int arr[], int idx, int size, int sum1, int sum2, int count1, int count2, int* group) { // 已找到解或处理完所有元素,直接返回 if (found || idx == size) { if (!found && idx == size && sum1 == sum2 && abs(count1 - count2) <= 2) { found = 1; } return; } // 尝试将当前元素放入第一组 group[idx] = 1; helper(arr, idx + 1, size, sum1 + arr[idx], sum2, count1 + 1, count2, group); if (found) return; // 找到解就停止回溯 // 尝试将当前元素放入第二组 group[idx] = 2; helper(arr, idx + 1, size, sum1, sum2 + arr[idx], count1, count2 + 1, group); if (found) return; // 回溯:当前元素暂不归属任何组 group[idx] = 0; } // 递归输出子数组元素(替代循环) void print_subarray(int arr[], int* group, int idx, int size, int target_group, int first) { if (idx == size) { printf("}"); return; } if (group[idx] == target_group) { if (!first) { printf(", "); } printf("%d", arr[idx]); print_subarray(arr, group, idx + 1, size, target_group, 0); } else { print_subarray(arr, group, idx + 1, size, target_group, first); } } // 题目要求的固定签名函数 void almost_balanced_partition(int arr[], int size) { found = 0; int* group = (int*)malloc(sizeof(int) * size); if (!group) return; // 递归初始化标记数组(无循环) void init_group(int idx, int size, int* group) { if (idx == size) return; group[idx] = 0; init_group(idx + 1, size, group); } init_group(0, size, group); // 调用递归辅助函数 helper(arr, 0, size, 0, 0, 0, 0, group); if (found) { // 输出第一组 printf("{"); print_subarray(arr, group, 0, size, 1, 1); printf(" and "); // 输出第二组 printf("{"); print_subarray(arr, group, 0, size, 2, 1); printf("\n"); } else { printf("No valid partition found.\n"); } free(group); } // 测试示例 int main() { int arr1[] = {1, 0, 1, 0}; almost_balanced_partition(arr1, 4); // 输出{1, 0, 0}和{1}或其他有效划分 int arr2[] = {2, 2, 3, 3}; almost_balanced_partition(arr2, 4); // 输出{2, 3}和{2, 3} int arr3[] = {1, 2, 3, 4, 5}; almost_balanced_partition(arr3, 5); // 输出{1, 2, 5}和{3,4}(和为8,数量差1) return 0; }
关键细节说明
- 标记数组:用
group数组记录每个元素的归属(1=第一组,2=第二组),递归过程中通过回溯更新标记。 - 无循环实现:所有数组遍历(初始化标记数组、输出子数组)都用递归完成,完全符合题目要求。
- 提前终止:一旦找到有效划分,
found标志设为1,后续递归直接返回,避免冗余计算。 - 输出格式:
print_subarray函数递归遍历数组,只输出目标组的元素,严格按照{元素1,元素2,...}的格式输出。
注意事项
- 如果数组总和为奇数,直接不可能满足和相等的条件,可在主函数开头加入判断优化(代码中未实现)。
- 递归深度等于数组大小,对于过大的数组可能导致栈溢出,若需处理大数据量可考虑尾递归优化(取决于编译器支持)。
内容的提问来源于stack exchange,提问作者Wael Jaber
相关产品推荐
相关产品推荐

