力扣第39题:组合总和(C语言解法)
题目描述
在一个无重复元素的数组 candidates
中找到所有和为目标值 target
的组合。数组中的数字可以多次使用,且组合中的元素按非递减顺序排列。
示例:
输入:candidates = [2,3,6,7], target = 7
输出:[[7],[2,2,3]]
解释:7 可以由 [7] 或 [2,2,3] 组合得到。
注意:
- 所有输入的数字是正整数。
- 结果中的每个组合按非递减顺序排列。
解题思路
本题的关键是找出所有可能的组合,可以通过回溯法来解决。回溯的核心是:
- 从每个元素开始,尝试将其加入当前组合,并递归计算剩余的目标值。
- 如果目标值为
0
,说明找到了一个合法组合;如果小于0
,则当前组合无效,回溯到上一层。 - 每次递归结束后,移除最近加入的数字,尝试新组合。
思路步骤
- 初始化结果数组用于存储所有组合。
- 使用回溯函数递归生成所有组合:
- 如果
target
为0
,将当前组合加入结果。 - 如果
target
小于0
,返回上一层递归。 - 对每个数字递归加入到组合中,继续递归并传递剩余目标值。
- 如果
- 最终返回包含所有组合的结果数组。
C语言代码实现
#include <stdio.h>
#include <stdlib.h>// 定义动态数组用于存储结果
typedef struct {int** data;int* columnSizes;int size;int capacity;
} ResultArray;// 初始化结果数组
ResultArray* createResultArray() {ResultArray* result = (ResultArray*)malloc(sizeof(ResultArray));result->data = (int**)malloc(100 * sizeof(int*));result->columnSizes = (int*)malloc(100 * sizeof(int));result->size = 0;result->capacity = 100;return result;
}// 将组合添加到结果数组中
void addResult(ResultArray* result, int* combination, int length) {if (result->size >= result->capacity) {result->capacity *= 2;result->data = (int**)realloc(result->data, result->capacity * sizeof(int*));result->columnSizes = (int*)realloc(result->columnSizes, result->capacity * sizeof(int));}result->data[result->size] = (int*)malloc(length * sizeof(int));for (int i = 0; i < length; i++) {result->data[result->size][i] = combination[i];}result->columnSizes[result->size] = length;result->size++;
}// 回溯函数
void backtrack(int* candidates, int candidatesSize, int target, int* combination, int length, int start, ResultArray* result) {if (target == 0) { // 找到一个组合addResult(result, combination, length);return;}if (target < 0) return; // 当前组合无效for (int i = start; i < candidatesSize; i++) {combination[length] = candidates[i];backtrack(candidates, candidatesSize, target - candidates[i], combination, length + 1, i, result);}
}// 主函数:组合总和
int** combinationSum(int* candidates, int candidatesSize, int target, int* returnSize, int** returnColumnSizes) {ResultArray* result = createResultArray();int* combination = (int*)malloc(target * sizeof(int)); // 存储单个组合// 调用回溯函数backtrack(candidates, candidatesSize, target, combination, 0, 0, result);// 设置返回值*returnSize = result->size;*returnColumnSizes = result->columnSizes;return result->data;
}// 测试代码
int main() {int candidates[] = {2, 3, 6, 7};int target = 7;int returnSize;int* returnColumnSizes;int** result = combinationSum(candidates, sizeof(candidates) / sizeof(candidates[0]), target, &returnSize, &returnColumnSizes);printf("组合总和的结果为:\n");for (int i = 0; i < returnSize; i++) {printf("[");for (int j = 0; j < returnColumnSizes[i]; j++) {printf("%d", result[i][j]);if (j < returnColumnSizes[i] - 1) printf(", ");}printf("]\n");free(result[i]);}free(result);free(returnColumnSizes);return 0;
}
代码解析
1. 初始化结果数组
定义一个 ResultArray
结构体,包含数据数组 data
、列大小数组 columnSizes
、当前大小 size
和容量 capacity
。通过 createResultArray
函数初始化一个动态数组。
ResultArray* createResultArray() {ResultArray* result = (ResultArray*)malloc(sizeof(ResultArray));result->data = (int**)malloc(100 * sizeof(int*));result->columnSizes = (int*)malloc(100 * sizeof(int));result->size = 0;result->capacity = 100;return result;
}
2. 添加组合到结果数组
addResult
函数用于将找到的合法组合存储到结果数组中。如果容量不足,使用 realloc
动态扩展容量。
void addResult(ResultArray* result, int* combination, int length) {if (result->size >= result->capacity) {result->capacity *= 2;result->data = (int**)realloc(result->data, result->capacity * sizeof(int*));result->columnSizes = (int*)realloc(result->columnSizes, result->capacity * sizeof(int));}result->data[result->size] = (int*)malloc(length * sizeof(int));for (int i = 0; i < length; i++) {result->data[result->size][i] = combination[i];}result->columnSizes[result->size] = length;result->size++;
}
3. 回溯函数
backtrack
函数用于递归生成每一种可能的组合:
- 如果
target == 0
,说明找到了一个符合要求的组合,调用addResult
。 - 如果
target < 0
,则组合无效,直接返回。 - 否则,遍历从
start
开始的候选数字,并递归调用backtrack
函数。
void backtrack(int* candidates, int candidatesSize, int target, int* combination, int length, int start, ResultArray* result) {if (target == 0) {addResult(result, combination, length);return;}if (target < 0) return;for (int i = start; i < candidatesSize; i++) {combination[length] = candidates[i];backtrack(candidates, candidatesSize, target - candidates[i], combination, length + 1, i, result);}
}
4. 主函数
combinationSum
函数负责初始化组合数组 combination
,调用 backtrack
寻找所有组合,设置返回结果的大小和列大小数组,返回结果数组。
int** combinationSum(int* candidates, int candidatesSize, int target, int* returnSize, int** returnColumnSizes) {ResultArray* result = createResultArray();int* combination = (int*)malloc(target * sizeof(int)); // 存储单个组合backtrack(candidates, candidatesSize, target, combination, 0, 0, result);*returnSize = result->size;*returnColumnSizes = result->columnSizes;return result->data;
}