0
点赞
收藏
分享

微信扫一扫

Jenkins的使用

月半小夜曲_ 2024-12-02 阅读 8

力扣78题详解:C语言实现子集问题

题目描述

给定一个不含重复元素的整数数组 nums,返回其所有可能的子集(幂集)。
说明:解集不能包含重复的子集,顺序无关。

示例

输入nums = [1,2,3]
输出

[
[],
[1],
[2],
[3],
[1,2],
[1,3],
[2,3],
[1,2,3]
]

解题思路

1. 子集的总数

对于包含 n n n 个元素的数组,其所有子集的数量为 2 n 2^n 2n
例如,数组 [1, 2, 3] 的子集总数为 2 3 = 8 2^3 = 8 23=8

2. 回溯法

采用回溯法逐步构建子集:

  • 每次递归调用选择是否将当前数字加入子集中。
  • 遍历所有可能的选择。

代码实现

以下是C语言的完整实现:

#include <stdio.h>
#include <stdlib.h>

void backtrack(int* nums, int numsSize, int** result, int* returnColumnSizes, int* subset, int subsetSize, int start, int* returnSize) {
    // 创建一个当前子集的副本
    result[*returnSize] = (int*)malloc(subsetSize * sizeof(int));
    for (int i = 0; i < subsetSize; i++) {
        result[*returnSize][i] = subset[i];
    }
    returnColumnSizes[*returnSize] = subsetSize;
    (*returnSize)++;

    // 继续生成子集
    for (int i = start; i < numsSize; i++) {
        subset[subsetSize] = nums[i];
        backtrack(nums, numsSize, result, returnColumnSizes, subset, subsetSize + 1, i + 1, returnSize);
    }
}

int** subsets(int* nums, int numsSize, int* returnSize, int** returnColumnSizes) {
    int maxSubsets = 1 << numsSize; // 子集总数是 2^n
    int** result = (int**)malloc(maxSubsets * sizeof(int*));
    *returnColumnSizes = (int*)malloc(maxSubsets * sizeof(int));
    *returnSize = 0;

    int* subset = (int*)malloc(numsSize * sizeof(int)); // 临时存储一个子集
    backtrack(nums, numsSize, result, *returnColumnSizes, subset, 0, 0, returnSize);

    free(subset);
    return result;
}

int main() {
    int nums[] = {1, 2, 3};
    int numsSize = sizeof(nums) / sizeof(nums[0]);
    int returnSize;
    int* returnColumnSizes;
    int** result = subsets(nums, numsSize, &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("]");
        if (i < returnSize - 1) printf(",");
        printf("\n");
    }
    printf("]\n");

    // 释放内存
    for (int i = 0; i < returnSize; i++) {
        free(result[i]);
    }
    free(result);
    free(returnColumnSizes);

    return 0;
}

代码详解

1. 回溯函数 backtrack

void backtrack(int* nums, int numsSize, int** result, int* returnColumnSizes, int* subset, int subsetSize, int start, int* returnSize)
参数解析:
  • nums: 输入数组。
  • numsSize: 数组的长度。
  • result: 存储所有子集的数组。
  • returnColumnSizes: 每个子集的长度。
  • subset: 当前子集的临时存储。
  • subsetSize: 当前子集的大小。
  • start: 开始选择元素的索引。
  • returnSize: 当前子集的总数。
核心逻辑:
  1. 保存当前子集

    result[*returnSize] = (int*)malloc(subsetSize * sizeof(int));
    for (int i = 0; i < subsetSize; i++) {
        result[*returnSize][i] = subset[i];
    }
    returnColumnSizes[*returnSize] = subsetSize;
    (*returnSize)++;
    
  2. 递归选择下一个元素

    for (int i = start; i < numsSize; i++) {
        subset[subsetSize] = nums[i];
        backtrack(nums, numsSize, result, returnColumnSizes, subset, subsetSize + 1, i + 1, returnSize);
    }
    

2. 主函数 subsets

  1. 计算最大子集数量
    使用位运算 2 n 2^n 2n

    int maxSubsets = 1 << numsSize;
    
  2. 动态分配存储空间

    int** result = (int**)malloc(maxSubsets * sizeof(int*));
    *returnColumnSizes = (int*)malloc(maxSubsets * sizeof(int));
    
  3. 调用回溯函数

    backtrack(nums, numsSize, result, *returnColumnSizes, subset, 0, 0, returnSize);
    

输出示例

运行程序,输入 nums = [1, 2, 3],输出:

[
[],
[1],
[2],
[3],
[1, 2],
[1, 3],
[2, 3],
[1, 2, 3]
]
举报

相关推荐

0 条评论