当前位置: 首页 > news >正文

代码随想录算法训练营第二十三天|Day23 回溯算法

39. 组合总和

题目链接/文章讲解:https://programmercarl.com/0039.%E7%BB%84%E5%90%88%E6%80%BB%E5%92%8C.html

视频讲解:https://www.bilibili.com/video/BV1KT4y1M7HJ

思路

int* path;
int pathTop;
int** ans;
int ansTop;
int* length;
void backTracking(int target, int index, int* candidates, int candidatesSize, int sum) {if(sum >= target) {if(sum == target) {int* tempPath = (int*)malloc(sizeof(int) * pathTop);int j;for(j = 0; j < pathTop; j++) {tempPath[j] = path[j];}ans[ansTop] = tempPath;length[ansTop++] = pathTop;}return ;}int i;for(i = index; i < candidatesSize; i++) {sum+=candidates[i];path[pathTop++] = candidates[i];backTracking(target, i, candidates, candidatesSize, sum);sum-=candidates[i];pathTop--;}
}int** combinationSum(int* candidates, int candidatesSize, int target, int* returnSize, int** returnColumnSizes){path = (int*)malloc(sizeof(int) * 50);ans = (int**)malloc(sizeof(int*) * 200);length = (int*)malloc(sizeof(int) * 200);ansTop = pathTop = 0;backTracking(target, 0, candidates, candidatesSize, 0);*returnSize = ansTop;*returnColumnSizes = (int*)malloc(sizeof(int) * ansTop);int i;for(i = 0; i < ansTop; i++) {(*returnColumnSizes)[i] = length[i];}return ans;
}

学习反思

代码定义了几个全局变量:

  • "path"是一个数组,用于存储当前正在探索的数字组合。
  • "pathTop"是"path"数组中下一个可用位置的索引。
  • "ans"是一个二维数组,用于存储所有有效的数字组合。
  • "ansTop"是"ans"数组中下一个可用位置的索引。
  • "length"是一个数组,用于存储"ans"数组中每个组合的长度。

"backTracking"函数是主要的递归函数,它探索所有可能的组合。它接收目标值、当前候选数数组的索引、候选数数组、候选数数组的大小和当前数字组合的和作为参数。

该函数首先检查当前和是否大于或等于目标值。如果是,它再检查和是否等于目标值。如果是,它创建一个名为"tempPath"的新数组,并将当前组合从"path"数组复制到它。然后,它将"tempPath"数组添加到"ans"数组中,并将组合的长度存储在"length"数组中。最后,它递增"ansTop"变量。然后,该函数继续探索候选数数组中的下一个数字。它通过从当前索引迭代到候选数数组的末尾来实现。对于每个数字,它将其添加到和中,将其添加到"path"数组中,并使用更新后的参数递归调用"backTracking"函数。在递归调用之后,它更新和路径变量以移除添加的数字,实际上回溯到先前的状态。最后,"combinationSum"函数初始化全局变量,调用"backTracking"函数,并设置返回数组的大小和列大小。

40.组合总和II

题目链接/文章讲解:https://programmercarl.com/0040.%E7%BB%84%E5%90%88%E6%80%BB%E5%92%8CII.html

视频讲解:https://www.bilibili.com/video/BV12V4y1V73A

思路

int* path;
int pathTop;
int** ans;
int ansTop;
int* length;
int cmp(const void* a1, const void* a2) {return *((int*)a1) - *((int*)a2);
}
void backTracking(int* candidates, int candidatesSize,  int target, int sum, int startIndex) {if(sum >= target) {if(sum == target) {int* tempPath = (int*)malloc(sizeof(int) * pathTop);int j;for(j = 0; j < pathTop; j++) {tempPath[j] = path[j];}length[ansTop] = pathTop;ans[ansTop++] = tempPath;}return ;}int i;for(i = startIndex; i < candidatesSize; i++) {if(i > startIndex && candidates[i] == candidates[i-1])continue;path[pathTop++] = candidates[i];sum += candidates[i];backTracking(candidates, candidatesSize, target, sum, i + 1);sum -= candidates[i];pathTop--;}
}
int** combinationSum2(int* candidates, int candidatesSize, int target, int* returnSize, int** returnColumnSizes){path = (int*)malloc(sizeof(int) * 50);ans = (int**)malloc(sizeof(int*) * 100);length = (int*)malloc(sizeof(int) * 100);pathTop = ansTop = 0;qsort(candidates, candidatesSize, sizeof(int), cmp);backTracking(candidates, candidatesSize, target, 0, 0);*returnSize = ansTop;*returnColumnSizes = (int*)malloc(sizeof(int) * ansTop);int i;for(i = 0; i < ansTop; i++) {(*returnColumnSizes)[i] = length[i];}return ans;
}

学习反思

在回溯算法之前,对候选数数组进行了快速排序。通过将相同的元素放在一起,可以避免在搜索过程中出现重复的组合。这样做可以减少递归调用的次数,从而提高算法的效率。其次,在递归调用的过程中,添加了一个判断条件。当遍历到同一层级的相同元素时,跳过对其的处理。这样可以避免产生重复的组合,进一步提高算法的效率。此外,对动态分配的数组也进行了一些调整。在ans数组中,不再使用ansTop指针来记录数组元素的位置,而是直接将ans数组中的每个元素与length数组中的相应位置关联起来。这样可以更方便地管理组合的长度信息。

131.分割回文串

题目链接/文章讲解:

https://programmercarl.com/0131.%E5%88%86%E5%89%B2%E5%9B%9E%E6%96%87%E4%B8%B2.html

视频讲解:https://www.bilibili.com/video/BV1c54y1e7k6

思路

char** path;
int pathTop;
char*** ans;
int ansTop = 0;
int* ansSize;
void copy() {char** tempPath = (char**)malloc(sizeof(char*) * pathTop);int i;for(i = 0; i < pathTop; i++) {tempPath[i] = path[i];}ans[ansTop] = tempPath;ansSize[ansTop++] = pathTop;
}
bool isPalindrome(char* str, int startIndex, int endIndex) {while(endIndex >= startIndex) {if(str[endIndex--] != str[startIndex++])return 0;}return 1;
}
char* cutString(char* str, int startIndex, int endIndex) {char* tempString = (char*)malloc(sizeof(char) * (endIndex - startIndex + 2));int i;int index = 0;for(i = startIndex; i <= endIndex; i++)tempString[index++] = str[i];tempString[index] = '\0';return tempString;
}
void backTracking(char* str, int strLen,  int startIndex) {if(startIndex >= strLen) {copy();return ;}int i;for(i = startIndex; i < strLen; i++) {if(isPalindrome(str, startIndex, i)) {path[pathTop++] = cutString(str, startIndex, i);}else {continue;}backTracking(str, strLen, i + 1);pathTop--;}
}char*** partition(char* s, int* returnSize, int** returnColumnSizes){int strLen = strlen(s);path = (char**)malloc(sizeof(char*) * strLen);ans = (char***)malloc(sizeof(char**) * 40000);ansSize = (int*)malloc(sizeof(int) * 40000);ansTop = pathTop = 0;backTracking(s, strLen, 0);*returnSize = ansTop;*returnColumnSizes = (int*)malloc(sizeof(int) * ansTop);int i;for(i = 0; i < ansTop; ++i) {(*returnColumnSizes)[i] = ansSize[i];}return ans;
}

学习反思

  1. 将输入的字符串转换为字符数组,以便于通过索引访问和取子串。
  2. 定义一个辅助函数isPalindrome,使用双指针法判断子串是否为回文字符串。
  3. 初始化结果数组result和切割方案数组path。
  4. 定义回溯函数backtracking,传入参数startIndex表示当前要切割的子串的起始索引。
  5. 终止条件为startIndex超过字符串长度,此时收集切割方案path并添加到结果数组result中。
  6. 遍历从startIndex到字符串末尾的所有子串,判断子串是否为回文字符串。如果是,将子串添加到切割方案path中,然后递归调用backtracking函数来寻找下一个起始位置的子串。
  7. 在递归调用之后,如果切割方案path非空,将最后一个元素弹出,进行回溯操作。
  8. 最后调用backtracking函数,startIndex初始为0,完成递归回溯的过程。
  9. 返回结果数组result。

在Swift中,使用数组来存储结果集和切割方案,通过append和removeLast方法来添加和移除元素。通过回溯算法,可以找到所有满足条件的切割方案。时间复杂度为O(N * 2^N)

总结

对回溯算法有了更深刻的认识,加油!!!


http://www.mrgr.cn/news/56051.html

相关文章:

  • 等保测评2.0——Windows系统测评指导书
  • 程序描述语言
  • 《深度学习》Dlib、OpenCV 关键点定位 原理及案例解析
  • RabbitMQ 入门(八)SpringAMQP消息转换器
  • 保研推荐信模板
  • IDEA如何查看所有的断点(Breakpoints)并关闭
  • 图纸加密软件哪个好?2024年图纸加密软件Top10排行榜最新出炉!
  • 干货分享!如何选择一个可靠的斗篷工具?
  • 海康设备视频平台/视频流协议在EasyCVR私有化视频平台中的应用
  • Java全栈经典面试题剖析4】JavaSE高级 -- 包装类,String, 类方法
  • 多线程初阶(九):线程池 ThreadPoolExecutor 工厂模式
  • 03:【HAL库】外部中断的使用
  • YOLOv11算法解析
  • Java全栈经典面试题剖析6】JavaSE高级 -- 文件、IO流、序列化
  • 【Fargo】11: pacing 参数不生效:同步调整采集码率
  • 【代码随想录Day48】图论Part01
  • 永恒之蓝漏洞
  • 华为od面试手撕代码真题题型6——传统双指针
  • 贝叶斯决策论
  • 【vue2.7.16系列】手把手教你搭建后台系统__provider绑定类标识(11)
  • 【C#】调用本机AI大模型流式返回
  • typescript 中的类型推断
  • 「C/C++」C++ STL容器库 之 std::string 字符串类
  • 银行软件测试有哪些测试点?一般银行的软件测试工作流程有哪些?
  • 2226733-37-3,Mal-amido-PEG24-NHS是一种结合了马来酰亚胺和聚乙二醇的活性酯化合物
  • 医疗健康行业获客难?来看这位区域总经理的业绩增长破局之道