力扣第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行业的大佬。