代码随想录算法训练营day22

4 阅读2分钟

77.组合回溯 1.理解递归和回溯之间的关系 2.简化算法需要考虑剪支 3.是否返回值需要根据情况进行判断

非剪支版本

class Solution {
public:
    vector<vector<int>> result;//全局变量,用于存储combine的结果
    vector<int> tmp;//用于存储临时结果
    //不需要返回值,所以设置递归函数为
    void recount(int n,int k,int index){
        //递归返回情况
        if(tmp.size()==k){
            result.push_back(tmp);
            return;//当tmp中存储k个数时,即可返回
        }
        //采用循环处理
        for(int i=index;i<=n;i++){
            //将第i个元素存入tmp当中
            tmp.push_back(i);
            //执行递归
            recount(n,k,i+1);
            //回溯
            tmp.pop_back();
        }

    }
    vector<vector<int>> combine(int n, int k) {
        //采用递归方法,不断进行回溯递归
       
        int index=1;//统计开始时的下标
        recount(n,k,index);
        return result;
    }
};

剪支版本

class Solution {
public:
    vector<vector<int>> result;//全局变量,用于存储combine的结果
    vector<int> tmp;//用于存储临时结果
    //不需要返回值,所以设置递归函数为
    void recount(int n,int k,int index){
        //递归返回情况
        if(tmp.size()==k){
            result.push_back(tmp);
            return;//当tmp中存储k个数时,即可返回
        }
        //采用循环处理
        for(int i=index;i<=n-(k-tmp.size())+1;i++){//此处进行了剪支
            //将第i个元素存入tmp当中
            tmp.push_back(i);
            //执行递归
            recount(n,k,i+1);
            //回溯
            tmp.pop_back();
        }

    }
    vector<vector<int>> combine(int n, int k) {
        //采用递归方法,不断进行回溯递归
       
        int index=1;//统计开始时的下标
        recount(n,k,index);
        return result;
    }
};

216 组合综合三 1.需要注意,在执行递归传入的参数时什么,不是index,是当前的i!!! 2.剪支需要思考特殊的条件

class Solution {
private:
    vector<vector<int>> result;//用于存储组合总和结果
    vector<int> tmp;//用于存储临时组合
    int combinesum=0;//记录组合数之和
    //采用递归三部法设计递归函数
    void travelsum(int k,int n,int index){//index指向递归开始的数据下标
       //递归终止条件
       if(tmp.size()==k){//满足k个数时
       //再次判断是否满足和等于n
          if(combinesum==n)
            result.push_back(tmp);
            return;
       }
       //剪支
       if(combinesum>n){
        return;
       }
       //单层递归逻辑
       for(int i=index;i<=9;i++){
        tmp.push_back(i);
        combinesum=combinesum+i;
        travelsum(k,n,i+1);
        //回溯
        combinesum=combinesum-i;
        tmp.pop_back();
       }
       return;
       }
public:
    vector<vector<int>> combinationSum3(int k, int n) {
        result.clear();
        tmp.clear();
        travelsum(k,n,1);
        return result;
    }
};

17.电话号码的字母组合 参考上述两题,需要注意的是i的取值范围变化

class Solution {
private:
    //设置数字和字母对应的二维映射
    const string letterMap[10] = {
    "", // 0
    "", // 1
    "abc", // 2
    "def", // 3
    "ghi", // 4
    "jkl", // 5
    "mno", // 6
    "pqrs", // 7
    "tuv", // 8
    "wxyz", // 9
};
   //在之前组合数字的基础上进行改进
    vector<string> result;//用于存储最后结果
    string cur;//存储单次递归的结果
    void combinletter(string digits,int index){
        //递归终止条件
        if(cur.size()==digits.size()){
            result.push_back(cur);
            return;
        }
        int digit = digits[index] - '0';        // 将index指向的数字转为int
        string letters = letterMap[digit];  
        //执行单层递归
        for(int i=0;i<letters.size();i++){//在index所指的数字所能代表的字母中取值
             cur.push_back(letters[i]);
             combinletter(digits,index+1);
             cur.pop_back();
        }
        return;
    }

public:
    vector<string> letterCombinations(string digits) {
        result.clear();
        cur.clear();
        combinletter(digits,0);
        return result;
    }
};