目录
题目描述:
有效 IP 地址 正好由四个整数(每个整数位于 0 到 255 之间组成,且不能含有前导 0),整数之间用 '.' 分隔。
例如:"0.1.2.201" 和 "192.168.1.1" 是 有效 IP 地址,但是 "0.011.255.245"、"192.168.1.312" 和 "192.168@1.1" 是 无效 IP 地址。
给定一个只包含数字的字符串 s ,用以表示一个 IP 地址,返回所有可能的有效 IP 地址,这些地址可以通过在 s 中插入 '.' 来形成。你 不能 重新排序或删除 s 中的任何数字。你可以按 任何 顺序返回答案。
也属于分割问题。像上一题一样startIndex就表示分割线。
分割问题我真,上一道题是三维数组让我头疼,这道题代码逻辑我搞不清楚!
粘个代码随想录代码之后看!
//记录结果
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** ret;
int ret_num;
int* path;
int path_num;
int *len;
void backtracking(int* nums,int numsSize,int startIndex){
//收获结果
int* temp=(int*)malloc(sizeof(int)*path_num);
for(int i=0;i<path_num;i++){
temp[i]=path[i];
}
len[ret_num]=path_num;
ret[ret_num++]=temp;
//终止条件
if(startIndex>=numsSize){
return ;
}
//单层处理
for(int i=startIndex;i<numsSize;i++){
path[path_num++]=nums[i];
//递归
backtracking(nums,numsSize,i+1);
//回溯
path_num--;
}
}
int** subsets(int* nums, int numsSize, int* returnSize, int** returnColumnSizes){
ret=(int**)malloc(sizeof(int*)*1025);
path=(int*)malloc(sizeof(int)*numsSize);
len=(int**)malloc(sizeof(int*)*1025);
ret_num=path_num=0;
backtracking(nums,numsSize,0);
*returnSize=ret_num;
*returnColumnSizes = malloc(sizeof(int)*ret_num);
for(int i=0;i<ret_num;i++){
(*returnColumnSizes)[i]=len[i];
}
return ret;
}
90. 子集 II
题目描述:
给你一个整数数组 nums ,其中可能包含重复元素,请你返回该数组所有可能的子集(幂集)。
解集 不能 包含重复的子集。返回的解集中,子集可以按 任意顺序 排列。
与78. 子集不同点在于:78规范了数组中元素只出现一次各不相同,而本题中没有此要求。
我的想法:(树枝去重)根据与78.的差异,想到将数组排序后去重再向78.一样收割结果。可以在递归开始前对数组进行去重,也可以在递归的单层处理过程中对与前者相同的元素不做递归操作,如下面代码中被注释掉的一行:
//单层处理
for(int i=startIndex;i<numsSize;i++){
// if(i>0&&nums[i]==nums[i-1]) continue;
path[path_num++]=nums[i];
backtracking(nums,numsSize,i+1);
path_num--;
很遗憾,这样行不通。会漏掉解。执行结果的差异如下:
而正确的做法应该是数层去重。
int** ret;
int ret_num;
int* path;
int path_num;
int *len;
int *state; //记录数组中元素的使用状态
int cmp_int(const void* e1,const void* e2){
return *(int*)e1-*(int*)e2;
}
void backtracking(int* nums,int numsSize,int startIndex){
//收割结果
int* temp=(int*)malloc(sizeof(int)*path_num);
for(int i=0;i<path_num;i++){
temp[i]=path[i];
}
len[ret_num]=path_num;
ret[ret_num++]=temp;
//终止判断
if(startIndex>=numsSize){
return ;
}
//单层处理
for(int i=startIndex;i<numsSize;i++){
//树枝去重
//state[i-1]==0表示做的是树枝去重
if(i>0&&nums[i]==nums[i-1]&&state[i-1]==0) continue;
path[path_num++]=nums[i];
//当前元素标记为使用
state[i]=1;
//递归
backtracking(nums,numsSize,i+1);
//回溯
path_num--;
//当前元素标记为未使用
state[i]=0;
}
}
int** subsetsWithDup(int* nums, int numsSize, int* returnSize, int** returnColumnSizes){
//排序
qsort(nums,numsSize,sizeof(int),cmp_int);
ret=(int**)malloc(sizeof(int*)*1025);
path=(int*)malloc(sizeof(int)*numsSize);
len=(int*)malloc(sizeof(int)*1025);
state=(int*)malloc(sizeof(int*)*numsSize);
memset(state,0,sizeof(int*)*numsSize);
ret_num=path_num=0;
backtracking(nums,numsSize,0);
*returnSize=ret_num;
*returnColumnSizes = malloc(sizeof(int)*ret_num);
for(int i=0;i<ret_num;i++){
(*returnColumnSizes)[i]=len[i];
}
return ret;
}
树枝去重与数层去重
数层去重后每个结果中元素可以有重复。(也就是数值重复的元素不再重新选择)
树枝去重后每个结果中没有重复元素。
//树枝去重
if(i>0&&nums[i]==nums[i-1]) continue;
//数层去重
if(i>0&&nums[i]==nums[i-1]&&state[i-1]==0) continue;