力扣78题解题思路

        力扣第78题:给定一个整形数组,可以以任何顺序返回他的所有子集,但是结集中不能包含重复的结集。

1.不用函数和指针:

        1.1.使用for循环

        好处是没有函数和指针,初学者也能看懂,坏处是能计算的数组个数和for循环的数量有关,需要计算的元素个数越多,for循环就需要越多,限制很大。

#include <stdio.h>

//有几个循环就能判断最多几个数字的子集,这个程序只有三个循环。只能判断三个数字及以下的子集,
int main(int argc, char const *argv[])
    int nums[] = {1,2,3};
    int i, j, k;
    int ret = sizeof(nums) / sizeof(nums[0]);
    
    //这个"[]"是空集,因为找不到办法判断空集,直接输出。
    printf("[]");
    
    for (i = 0; i < ret; i++)
    {
        //输出单个数字的子集
        printf("[%d]", nums[i]);
        for (j = i + 1; j < ret; j++)
        {
            //输出两个数字的子集
            printf("[%d,%d]", nums[i], nums[j]);
            for(k = j + 1; k < ret; k++)
            {
                //输出三个数字的子集
                printf("[%d,%d,%d]",nums[i], nums[j], nums[k]); 
            }
        }
    }
    return 0;
}


//自己给定数组元素
#include <stdio.h>
#include <math.h>

int main(int argc, char const *argv[])
{
    int Input[100], InuptNnums, output[100][100];
    
    printf("请输入数组元素个数: ");
    scanf("%d", &InuptNnums);
    printf("请依次输入数组元素: ");
    for(int i = 0; i < InuptNnums; i++)
    {
        scanf("%d", &Input[i]);
    }
    for(int i = 0; i < pow(2, InuptNnums); i++)
    {
        printf("[ ");
        for(int j = 0; j < InuptNnums; j++)
        {
            output[i][j] = (i & (0x1 << j)) >> j;
            if(output[i][j] == 1)
            {
                printf("%d,", Input[j]);
            }
        }
        printf("\b ]\n");
    }
    return 0;
}

        1.2字节偏移

        好处是没有了for循环的限制,可以判断任意长度的数组,缺点是空集依然是需要自己输出,而不是判断输出。

#include <stdio.h>
#include <math.h>

int main()
{
    int arr[3]={1,2,3};
    int len = sizeof(arr) / sizeof(arr[0]);

    printf("[]\n");
    for(int i = 1; i < pow(2,len); i++)
    {
        printf("[");
        for(int j = 0; j < i; j++)
        {
            if(((i >> j)&1)==1)
                printf("%d,",arr[j]);
        }
        printf("\b]\n");
    }
}

2.利用指针和函数

        力扣的官方答案上也有,不过力扣的官方答案只需要写子函数就可以了,没有主函数。

        指针用来申请堆空间存放子集,已经全部判断完成后用指针来指向子集并且输出,函数用来判断子集并且存放进堆空间。

        好处是所有子集都是判断出来的,可以很好的用来巩固知识。缺点是运用的知识属于c语言中比较复杂的内容,对于掌握不好的同学来说比较难理解,而且代码很长。

int main(int argc, char const *argv[])
{
    int nums[] = {1,2,3};

    // 集合元素的个数
    int size = sizeof(nums)/sizeof(nums[0]);

    // 子集个数
    int row = 1 << size;

    // 子集列
    int childnums[size * sizeof(int)];
    memset(childnums,0,size * sizeof(int));

    // 记录每个子集元素个数
    int colsize[row*sizeof(int)];

    // 申请堆空间,存放每一个子集的首元素地址(使用二级指针用来指向数组)
    int **allstr = (int **)calloc(row,sizeof(int *));

    //如果子集为空的判断
    if(allstr == NULL)
    {
        perror("calloc failed:");
        return -1;
    }

    //子集不为空的判断

    int col = 0;//初始化col

    for(int i = 0;i < row;i++)
    {
        col = 0;
        for(int j = 0;j < size;j++)
        {
            // 对i的每一位尝试构成子集
            if(i&(1 << j))
            {
                // 如果i的第j位的二进制位为真,则nums[j]元素录入子集(数组childnums中)
                childnums[col++] = nums[j];
            }
        }

        // 申请堆空间用于存放子集
        int*temp = (int *)calloc(col,sizeof(int));

        //将数组childnums中的元素复制到temp指向的堆空间中
        memcpy(temp,childnums,col*sizeof(int));

        // 将temp挂在allstr的某个子集(将temp中的元素给到allstr指针指向的某个数组空间中)
        allstr[i] = temp;

        // 记录每个子集的元素个数
        colsize[i] = col;
    }

    //输出子集
    for(int i = 0;i <row;i++)
    {
        printf("[");
        for(int j = 0;j < colsize[i];j++)
        {
            printf("%d",allstr[i][j]);
        }
        printf("]");
        printf("\n");
    }

    free(allstr);
    allstr = NULL;

    return 0;
}

        如果有错误或者可以改进的地方也欢迎大家指出批评,希望我的这篇内容可以帮助到你,也希望大家可以一起进步,早日成为IT行业的大佬。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值