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

server/2024/10/23 12:14:32/

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.ppmy.cn/server/134168.html

相关文章

sentinel原理源码分析系列(五)-构建调用链路

上节分析构建插槽链&#xff0c;Sentinel的资源调用好比一个个连续的检查口&#xff0c;能否通过&#xff0c;使用检查规则和统计指标&#xff0c;本章开始分析插槽&#xff0c;首先分析构建调用链路的两个插槽 构建调用链路 构建调用链路为指标统计搭建好结构&#xff0c;调…

git基础操作步骤

第一种情况&#xff1a; 对方已经建立了个空的仓库&#xff0c;我们复制其url到要提交的项目文件下&#xff0c;输入cmd&#xff0c; 首先 git config --global user.email “youexample.com” git config --global user.name “Your Name” 然后 git init git add . git com…

构建后端为etcd的CoreDNS的容器集群(一)、生成自签名证书

笔者拟使用官方的etcd和CoreDNS容器镜像生成带自签名的分布式DNS容器集群。按计划需做生成自签名证书、部署etcd集群、配置CoreDNS以使用etcd作为后端共三步&#xff0c;本文为第一步。 一、生成自签名证书 1、准备CFSSL工具 官网下载&#xff1a; [rootlocalhost ~]# cd /o…

uni-app 实现好看易用的抽屉效果

在移动应用开发中&#xff0c;抽屉效果是一种常用的用户界面设计&#xff0c;它能有效地节省空间&#xff0c;同时提供导航和其他功能。本文将介绍如何在uni-app中实现一个好看且易用的抽屉效果&#xff0c;帮助你提升应用的用户体验。 一、什么是抽屉效果&#xff1f; 抽屉效…

Gin 协程mysql客户端

一、Gin框架 mysql配置 这里选择yaml文件配置 二、配置读取 viper 读取yaml文件中对应配置 三、mysql 的协程客户端 文件位置 package databaseimport ("database/sql""fmt""github.com/spf13/viper""log""net/http"&quo…

BIMBase构思渲染,一个强大的免费渲染插件

最近设计圈的小伙伴们都在热议AI出图的魔力 试想一下 假如你只剩一两个小时就要交图/方案阶段性汇报 还要用V-Ray/Blender辛辛苦苦渲染一整天吗&#x1f623; 借助AI工具 设计师可以将更多的时间与精力放在创作构思上 而不是埋头于画图或等待渲染效果图 同时避免了因电脑…

基于PHP+MySQL+Vue的网上订餐系统

摘要 本文介绍了一个基于PHPMySQLVue技术的网上订餐系统。该系统旨在为用户提供便捷的在线订餐服务&#xff0c;同时提高餐厅的运营效率。系统后端采用PHP语言开发&#xff0c;利用MySQL数据库进行数据存储与管理&#xff0c;实现了用户注册登录、菜品浏览、购物车管理、订单提…

详解mac系统通过brew安装mongodb与使用

本文目录 一、通过brew安装MongoDB二、mongodb使用示例1、启动数据库2、创建/删除数据库3、创建/删除集合 三、MongoDB基本概念1&#xff09;数据库 (database)2&#xff09;集合 &#xff08;collection&#xff09;3) 文档&#xff08;document&#xff09;4&#xff09;mong…