代码随想录 | Day29 | 回溯算法:电话号码的字母组合&&组合总和

代码随想录 | Day29 | 回溯算法:电话号码的字母组合&&组合总和

关于这个章节,大家最好是对递归函数的理解要比较到位,听着b站视频课可能呢才舒服点,可以先去搜一搜关于递归函数的讲解,理解,再开始这个章节会比较好一些

我觉得回溯就是对传入递归函数的参数加加减减,加了的减掉,减了的加上

主要学习内容:

组合题目的模板

17.电话号码的字母组合

17. 电话号码的字母组合 - 力扣(LeetCode)

解法思路:

这道题其实主要的难点是要搞清楚模板里面的for循环到底在干些什么事情

20201123200304469树的每个分支其实就是每一次for循环产生的,每一层递归函数的for循环可以整整产生一层节点,比如第一层递归函数的for产生的就是要分别取a,b,c,一共循环三次,取出来三个数,所以第一层有三个节点

第二层也是类似,分别选了def,才有了ad,ae,af三个结果,所以有3*3=9个结果

而第一层的abc是数字2的集合,第二层的def是数字3的集合,所以每一层递归函数都是在遍历一个不同的数的集合,我们要做的就是让递归函数知道他这一层要遍历哪个数字的集合

1.函数参数和返回值

vector<string> res;
vector<string> s{"","","abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"};//0,1没有,从2开始对应
void backtracking(string str,string digits,int index)

res存放结果集,s存放数字对应的字符串

传入的参数,str相当于path,收集我们已经知道的答案

digits是题目中给的字符串,index传递本层递归函数要遍历哪个集合

2.终止条件

一个数字只选一个字母,所以只要我们收集的和题目给的字符串一样大,就是答案了

if(str.size()==digits.size())
{
	res.push_back(str);
	return;
}

3.本层代码逻辑

t表示的是我们这层递归函数选的哪个数字,是由字符串里面的数字转换过来的

s[t]对应我们选的字符串(abc还是def)

遍历自然就遍历我们选的这个字符串,从0遍历到它结束,因为它的每一个字符我们都得选一遍的

s[t][i]就是对应每个字母,我们压入字符串(这里就是把23这个例子的a压入了),然后进入下一层递归去选下一个字母(去选def里面的字母去了就)

递归的index就直接+1即可,因为我们要选的就是下一个数字对应的集合

递归结束,把刚刚压入的字母弹出(把a弹出,等i等于1压入b)

int t=(int)(digits[index]-'0');
for(int i=0;i<s[t].size();i++)
{
	str.push_back(s[t][i]);
	backtracking(str,digits,index+1);
    //回溯
    str.pop_back();
}

完整代码:

class Solution {
public:
    vector<string> res;
    vector<string> s{"","","abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"};
    void backtracking(string str,string digits,int index)
    {
        if(str.size()==digits.size())
        {
            res.push_back(str);
            return;
        }
        int t=(int)(digits[index]-'0');
        for(int i=0;i<s[t].size();i++)
        {
            str.push_back(s[t][i]);
            backtracking(str,digits,index+1);
            str.pop_back();
        }
    }
    vector<string> letterCombinations(string digits) {
        if(digits.size()==0)
            return res;
        string str;
        backtracking(str,digits,0);
        return res;
    }
};

注:digits如果为空传个空就是。

39.组合总和

39. 组合总和 - 力扣(LeetCode)

思路:

和之前的思路差不多组合总和III,就是之前每层遍历是从i+1开始,是为了防止出现重复的数字,现在遍历从i开始,因为本身的数可以重复取

1.函数返回值和参数

vector<vector<int>> res;
void backtracking(vector<int> path,int sum,int index,vector<int> candidates,int target)

res记录结果

path收集当前组合

sum当前集合的总和

index从哪个数开始

candidates题目给的数组

target题目给的目标值

2.终止条件

当前总和已经大于target了,没必要再递归了

如果大小等于target,收集结果

if(sum>target)
	return;
if(sum==target)
{
	res.push_back(path);
	return;
}

3.本层逻辑

额就是可以重复取当前数字,所以下一层递归函数传参传i而不是i+1,i+1可以避免取重复的数字

不太好理解的话大家可以画个图模拟一下

for(int i=index;i<candidates.size();i++)
{
	path.push_back(candidates[i]);
	backtracking(path,sum+candidates[i],i,candidates,target);
	path.pop_back();
}

完整代码:

class Solution {
public:
    vector<vector<int>> res;
    void backtracking(vector<int> path,int sum,int index,vector<int> candidates,int target)
    {
        if(sum>target)
            return;
        if(sum==target)
        {
            res.push_back(path);
            return;
        }
        for(int i=index;i<candidates.size();i++)
        {
            path.push_back(candidates[i]);
            backtracking(path,sum+candidates[i],i,candidates,target);
            path.pop_back();
        }
    }
    vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
        vector<int> path;
        backtracking(path,0,0,candidates,target);
        return res;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值