@ 代码随想录算法训练营第5周(C语言)|Day28(回溯)
Day28、回溯(包含题目 93.复原IP地址 78.子集 90.子集II )
93.复原IP地址
题目描述
给定一个只包含数字的字符串,复原它并返回所有可能的 IP 地址格式。
有效的 IP 地址 正好由四个整数(每个整数位于 0 到 255 之间组成,且不能含有前导 0),整数之间用 ‘.’ 分隔。
题目解答
char** result;
int resultTop;
//记录应该加入'.'的位置
int segments[3];
int isValid(char* s, int start, int end) {
if(start > end)
return 0;
if (s[start] == '0' && start != end) { // 0开头的数字不合法
return false;
}
int num = 0;
for (int i = start; i <= end; i++) {
if (s[i] > '9' || s[i] < '0') { // 遇到非数字字符不合法
return false;
}
num = num * 10 + (s[i] - '0');
if (num > 255) { // 如果大于255了不合法
return false;
}
}
return true;
}
//startIndex为起始搜索位置,pointNum为'.'对象
void backTracking(char* s, int startIndex, int pointNum) {
//若'.'数量为3,分隔结束
if(pointNum == 3) {
//若最后一段字符串符合要求,将当前的字符串放入result种
if(isValid(s, startIndex, strlen(s) - 1)) {
char* tempString = (char*)malloc(sizeof(char) * strlen(s) + 4);
int j;
//记录添加字符时tempString的下标
int count = 0;
//记录添加字符时'.'的使用数量
int count1 = 0;
for(j = 0; j < strlen(s); j++) {
tempString[count++] = s[j];
//若'.'的使用数量小于3且当前下标等于'.'下标,添加'.'到数组
if(count1 < 3 && j == segments[count1]) {
tempString[count++] = '.';
count1++;
}
}
tempString[count] = 0;
//扩容result数组
result = (char**)realloc(result, sizeof(char*) * (resultTop + 1));
result[resultTop++] = tempString;
}
return ;
}
int i;
for(i = startIndex; i < strlen(s); i++) {
if(isValid(s, startIndex, i)) {
//记录应该添加'.'的位置
segments[pointNum] = i;
backTracking(s, i + 1, pointNum + 1);
}
else {
break;
}
}
}
char ** restoreIpAddresses(char * s, int* returnSize){
result = (char**)malloc(0);
resultTop = 0;
backTracking(s, 0, 0);
*returnSize = resultTop;
return result;
}
题目总结
搞一个记录.位置的数组。
78.子集
题目描述
给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。
说明:解集不能包含重复的子集。
题目解答
int **res;
int reslen;
int *path;
int pathlen;
int *numscount;
void bfs(int* nums,int numsSize,int startindex){
//不用写终止条件
int*temp=(int*)malloc(sizeof(int)*pathlen);
for(int i=0;i<pathlen;i++){
temp[i]=path[i];
}
numscount[reslen]=pathlen;
res[reslen++]=temp;
for(int i=startindex;i<numsSize;i++){
path[pathlen++]=nums[i];
bfs(nums,numsSize,i+1);
pathlen--;
}
}
int** subsets(int* nums, int numsSize, int* returnSize, int** returnColumnSizes) {
res=(int**)malloc(sizeof(int*)*10000);
path=(int*)malloc(sizeof(int)*numsSize);
numscount=(int*)malloc(sizeof(int)*10000);
reslen=pathlen=0;
bfs(nums,numsSize,0);
*returnSize=reslen;
*returnColumnSizes=(int*)malloc(sizeof(int)*reslen);
for(int i=0;i<reslen;i++){
(*returnColumnSizes)[i]=numscount[i];
}
return res;
}
题目总结
不用写终止条件。
90.子集II
题目描述
给定一个可能包含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。
说明:解集不能包含重复的子集。
题目解答
int **res;
int reslen;
int *path;
int pathlen;
int *numscount;
int cmp(const void* a, const void* b) {
return *((int*)a) - *((int*)b);
}
void bfs(int *nums,int numsSize,int startindex,int *used){
int*temp=(int*)malloc(sizeof(int)*pathlen);
for(int i=0;i<pathlen;i++){
temp[i]=path[i];
}
numscount[reslen]=pathlen;
res[reslen++]=temp;
for(int i=startindex;i<numsSize;i++){
if(i>startindex&&nums[i]==nums[i-1]){
continue;
}
path[pathlen++]=nums[i];
//used[i]=true;
bfs(nums,numsSize,i+1,used);
pathlen--;
//used[i]=false;
}
}
int** subsetsWithDup(int* nums, int numsSize, int* returnSize, int** returnColumnSizes) {
res=(int**)malloc(sizeof(int*)*10000);
path=(int*)malloc(sizeof(int)*numsSize);
int *used=(int*)malloc(sizeof(int)*numsSize);
numscount=(int*)malloc(sizeof(int)*10000);
reslen=pathlen=0;
qsort(nums, numsSize, sizeof(int), cmp);
bfs(nums,numsSize,0,used);
*returnSize=reslen;
*returnColumnSizes=(int*)malloc(sizeof(int)*reslen);
for(int i=0;i<reslen;i++){
(*returnColumnSizes)[i]=numscount[i];
}
return res;
}
题目总结
宽度去重。