代码随想录算法训练营| 第77题. 组合, 216.组合总和III ,17.电话号码的字母组合

文章来源:https://programmercarl.com/回溯算法理论基础.html#题目分类

理论基础

  • 回溯的本质是穷举
  • 但是可以增加一些剪枝算法来进行优化
  • 回溯法解决的问题都可以抽象为树形结构,集合的大小构成了树的宽度,递归的深度决定了树的深度

第77题. 组合

文章来源:https://programmercarl.com/0077.组合.html#算法公开课
题目链接:https://leetcode.cn/problems/combinations/description/
视频链接:https://www.bilibili.com/video/BV1ti4y1L7cv/?vd_source=6cb513d59bf1f73f86d4225e9803d47b

class Solution {
public:
vector<vector<int>> res;
vector<int> path;
    void backtracking(int n,int k,int startIndex){
        //终止条件
        if(path.size()==k){
            res.push_back(path);
            return;
        }
        //否则继续进行回溯遍历
        for(int i=startIndex;i<=n;i++){
            path.push_back(i);
            //进行下一个元素的选择
            backtracking(n,k,i+1);
            path.pop_back();  //每push进入一个元素,回溯是就要将该元素再pop出去,以便能增加新的元素进去
        }
    }
    vector<vector<int>> combine(int n, int k) {
        backtracking(n,k,1);
        return res;
    }
};

216.组合总和III

文章链接:https://programmercarl.com/0216.组合总和III.html#算法公开课
题目链接:https://leetcode.cn/problems/combination-sum-iii/description/

  • 此题与上一题相比,关键在于多了path总和的计算,因此可在backtracking中增加一个sum参数,用来记录每一次backtracking时sum的值是多少。
class Solution {
public:
    vector<int> path;
    vector<vector<int>> res;
    void backtracking(int k,int n,int startIndex,int sum){
        if(path.size()==k&&sum==n){ 
            res.push_back(path);
            return;
        }
        for(int i=startIndex;i<=9;i++){
            if(i>n-sum) break;  //剪枝
            path.push_back(i);
            backtracking(k,n,i+1,sum+i);
            path.pop_back();
        }
    }
    vector<vector<int>> combinationSum3(int k, int n) {
        backtracking(k,n,1,0);
        return res;
    }
};

17.电话号码的字母组合

文章链接:https://programmercarl.com/0017.电话号码的字母组合.html#算法公开课
题目链接:https://leetcode.cn/problems/letter-combinations-of-a-phone-number/description/

一开始写的代码如下,会造成一些错误和不必要的运算

class Solution {
public:
    string path;
    vector<string> res;
    int n=0,index=0;
    unordered_map<char,vector<char>> map;
    void init(string digits){
        n=digits.size();
        map['2']={'a','b','c'};
        map['3']={'d','e','f'};
        map['4']={'g','h','i'};
        map['5']={'j','k','l'};
        map['6']={'m','n','o'};
        map['7']={'p','q','r','s'};
        map['8']={'t','u','v'};
        map['9']={'w','x','y','z'};
    }
    void backtracking(string digits,int index){
        if(index==n){
            res.push_back(path);
            return;
        }
        for(char i:map[digits[index]]){
            path.push_back(i);
            backtracking(digits,index+1);
            path.pop_back();
        }
    }
    vector<string> letterCombinations(string digits) {
        init(digits);
        backtracking(digits,0);
        return res;
    }
};

修改后:

  • 注意如果digits为空,则应该在主函数中加一句空情况
  • 全局参数可以不用定义的过多,不然显得很冗余
  • 将参数string digits改为const string& digits
class Solution {
public:
    string path;
    vector<string> res;
    unordered_map<char,vector<char>> map;
    void init(string digits){
        map['2']={'a','b','c'};
        map['3']={'d','e','f'};
        map['4']={'g','h','i'};
        map['5']={'j','k','l'};
        map['6']={'m','n','o'};
        map['7']={'p','q','r','s'};
        map['8']={'t','u','v'};
        map['9']={'w','x','y','z'};
    }
    void backtracking(const string& digits,int index){
        if(index==digits.size()){
            res.push_back(path);
            return;
        }
        for(char chr:map[digits[index]]){
            path.push_back(chr);
            backtracking(digits,index+1);
            path.pop_back();
        }
    }
    vector<string> letterCombinations(string digits) {
        if(digits.size()==0) return {};
        init(digits);
        backtracking(digits,0);
        return res;
    }
};
posted @   W-Vicky11  阅读(4)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示