力扣第39题:组合总和(C语言解法)

力扣第39题:组合总和(C语言解法)

题目描述

在一个无重复元素的数组 candidates 中找到所有和为目标值 target 的组合。数组中的数字可以多次使用,且组合中的元素按非递减顺序排列。

示例

c 复制代码
输入:candidates = [2,3,6,7], target = 7
输出:[[7],[2,2,3]]
解释:7 可以由 [7] 或 [2,2,3] 组合得到。

注意

  • 所有输入的数字是正整数。
  • 结果中的每个组合按非递减顺序排列。

解题思路

本题的关键是找出所有可能的组合,可以通过回溯法来解决。回溯的核心是:

  1. 从每个元素开始,尝试将其加入当前组合,并递归计算剩余的目标值。
  2. 如果目标值为 0,说明找到了一个合法组合;如果小于 0,则当前组合无效,回溯到上一层。
  3. 每次递归结束后,移除最近加入的数字,尝试新组合。

思路步骤

  1. 初始化结果数组用于存储所有组合。
  2. 使用回溯函数递归生成所有组合:
    • 如果 target0,将当前组合加入结果。
    • 如果 target 小于 0,返回上一层递归。
    • 对每个数字递归加入到组合中,继续递归并传递剩余目标值。
  3. 最终返回包含所有组合的结果数组。

C语言代码实现

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 函数初始化一个动态数组。

c 复制代码
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 动态扩展容量。

c 复制代码
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 函数。
c 复制代码
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 寻找所有组合,设置返回结果的大小和列大小数组,返回结果数组。

c 复制代码
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;
}
相关推荐
YuforiaCode8 分钟前
第十二届蓝桥杯 2021 C/C++组 直线
c语言·c++·蓝桥杯
知来者逆27 分钟前
计算机视觉——速度与精度的完美结合的实时目标检测算法RF-DETR详解
图像处理·人工智能·深度学习·算法·目标检测·计算机视觉·rf-detr
阿让啊31 分钟前
C语言中操作字节的某一位
c语言·开发语言·数据结构·单片机·算法
এ᭄画画的北北32 分钟前
力扣-160.相交链表
算法·leetcode·链表
拾忆-eleven1 小时前
C语言实战:用Pygame打造高难度水果消消乐游戏
c语言·python·pygame
爱研究的小陈1 小时前
Day 3:数学基础回顾——线性代数与概率论在AI中的核心作用
算法
渭雨轻尘_学习计算机ing2 小时前
二叉树的最大宽度计算
算法·面试
再睡一夏就好2 小时前
Linux常见工具如yum、vim、gcc、gdb的基本使用,以及编译过程和动静态链接的区别
linux·服务器·c语言·c++·笔记
BB_CC_DD2 小时前
四. 以Annoy算法建树的方式聚类清洗图像数据集,一次建树,无限次聚类搜索,提升聚类搜索效率。(附完整代码)
深度学习·算法·聚类
embedded_w3 小时前
U8G2在PC端模拟(C语言版本)
c语言