回溯算法在用到的时候,需要考虑下回溯算法模板:
1.确定回溯(递归)函数参数
2.确定递归终止条件
3.确定单层循环逻辑
其余的就是对于不同的题型,注意不同的细节了
题目:给定两个数n和k,返回[1,n]中所有k个数的组合,结果是个二维数组
解析:这道题相对于后面的几道来说,还是比较好理解的,需要关注的点就是题干说了是[1,n],所以startIndex是从1开始,且循环的起始条件是i := startIndex,每次递归都是进入下一层i+1;剪枝的先不写了,到时候能想出来就写,想不出来就算了
题目:找出所有相加之和为n的k个数的组合,且数的选择范围是从1-9,每个数只能用一次
解析:这道题因为要相加,所有在递归函数的终止条件中,还需要判断一层:如果加的和已经大于了n或者用的个数大于了K,就return;然后因为是从1开始,startIndex也是从1开始
题目:给定的是字符串,包含数字2-9,返回所有可以的字母组合,对应方式为键盘的九宫格
解析:首先需要定义一个map或者数组来维护一个数组和哪几个字母的映射关系,需要注意的第一点是,终止条件应该是给定字符串的长度和path的长度相等,就代表符合预期;然后startIndex是从0开始,那么代表的其实是字符串的下标;其余的注意点就是什么字符串按照下标取出来的结果是rune什么的,需要string下处理,这就是实现语言的层面了
题目:给定一个数组,其中无重复元素,但是可以多次取值;给定一个目标值target,求加起来等于target的组合
解析:这道题的startIndex是从0开始,然后递归函数的调用时,i不需要加1,因为可以取多次;别的好像也没什么需要注意的地方了
题目:给定数组和目标值,但是这个数组,里面有重复元素,比如[1,1,2],其中第一个1中只能用1次,但第一个1和第二个1可以一起用
解析:这道题就需要在脑海里构造一棵树,树的深度不用去重,但宽度的时候需要去重;而且需要先排序一下,将相同的元素都挨着;(这个时候的剪枝一般都需要排序);这道题的startIndex是从0开始的,在递归的时候,需要+1,因为每个数字在每个组合中只出现一次;与此同时这道题要同一个树枝可以重复,但同一树层不可以,那么在循环中的判断条件就是:
if i > startIndex && candidates[i] == candidates[i-1] {
continue // 注意是continue,不是return
}
题目:给定一个字符串s,要求分割出来的都是回文子串(正反读都一样,单个字母也算回文)
解析:这道题和之前的其实也很像,需要注意的就是终止条件;这道题的终止条件就是标志位到了整个给定字符串的最后,然后本题中由于需要在后面的逻辑中判断是回文才会追加到path中,所以不必在终止条件这里考虑别的,只看标志位到了就行;另外一个判断是回文后,追加进path中,截取数组的办法是右边界+1,这个是语法。
题目:给一个字符串如"25525511135",要求分割成有效的IP地址(第一位不为0,都是4段等)
解析:还是分割问题,和上一道的区别就是一来返回的是一维数组,二来是终止条件也多了点,分割线既要走到最后,还得path正好等于4;同时还需要主要截取数组的办法是右边界+1这个东西;还有判断是否为0的时候,因为是字符串,要和’0’来比等等,细节比较多
题目:给定一个数组,无重复元素,求所有可能的子集(包括空子集)
解析:这道题的思路就很简单了,直接按照上面的回溯思路,套模板,每层递归就追加进数组即可
题目:还是数组,但是有重复元素,求所有子集
解析:由于重复元素,所以要先排序;在for循环中,跳出条件为i > startIndex && nums[i] == nums[i-1],别的都一样
题目:给定数组,有重复元素,求递增子序列,要求至少两个元素
解析:框架还是回溯的框架,区别第一点是,终止条件是两个元素以上,且不能continue;第二点是要初始化一个map来存已经用过的值,防止重复使用(同一树层,for循环是横向,递归是纵向),另外的两个条件是,len(path) > 0 且 当前值小于path的最后一个值,此时也直接continue;
题目:给定一个数组,无重复数字,返回这个数组的全排列
解析:排列和组合的区别就不说了,需要注意的有这几点:1.终止条件是path的长度等于给定数组的长度;2.因为是要全排列,就不需要startIndex了,每次直接从0开始,但需要注意的是,在同一个树枝中不能有重复的,所以要像上一道一样,将用过的数存一个map,如果同一个树枝用过了,就continue(注意上一道题的map是用在同一个树层)
题目:给定一个数组,有重复数字,返回全排列,要不重复的
解析:要不重复的,根据之前的经验,要先排序,将大小相同的放在一起,然后终止条件和上一道题相同;同时由于是全排列,不需要startIndex了,都是从0开始循环;循环中的判断continue条件是:i > 0 && nums[i] == nums[i-1] && usedMap[i-1] == false
用来代表是在同一树层没有重复的元素,注意这道题的map中存的Key是下标,上一道的map的key是数组的元素的值