Day25(216.组合总和|||,17.电话号码的字母组合)

216.组合总和|||

题目链接:216. 组合总和 III - 力扣(LeetCode)

解题思路:这题和组合问题有着很多相似的地方,基本的解题思路和代码格式也是大同小异只是略有区别,相当于这题是在组合问题上加上了一个条件,即k个元素的组合的和为n。同样使用回溯算法来解决。用两个全局数据来保存数据,分别是path和result,每遍历一个数则向path里面压入一个数,若符合题目要求的话,则将该path压入result,然后进行回溯操作。

1、函数返回类型和传入参数:因为要遍历所有情况,所以没有返回值,而传入的参数是(int n , int k , int sum , int startindex)其中n,k是题目所给定的数值,sum是求k个数的总和,而startindex用来记录起始索引位置,防止出现重复组合。

2、终止条件:当path.size() == k的时候则终止,然后判断此时的sum是否和n相等,若相等的话则用result保存此时的path。

3、单层递归逻辑:将遍历到的数值压入path,根据startindex的值来求本层递归中for循环中的sum,当path.size() == k时候判断sum是否和n相等,若相等则把当前path压入resul,然后进行回溯操作。

代码实现:

class Solution {
private:
    vector<int>path;
    vector<vector<int>>result;
    void backtracing(int k ,int n ,int sum, int startindex){
        if( path.size() == k){
            if(sum == n){
            result.push_back(path);
            return;
            }
        }
        for(int i = startindex; i < n;i++){
            sum += i;
            path.push_back(i);
            backtracing(k, n, sum, i+1);
            sum -= i;
            path.pop_back();
        }
    }
public:
    vector<vector<int>> combinationSum3(int k, int n) {
        result.clear();
        path.clear();
        backtracing(k,n,0,1);
        return result;

    }
};

以上是使用回溯算法进行全局搜索的代码,然而在很多种情况下我们不需要进行继续递归搜索,所以应该进行剪枝操作。

1、当sum>n的时候就不再继续进行搜索了,直接返回。

2、当从startindex开始向后遍历完所有的元素也不能满足达到k个元素的时候停止递归。

此时的i的范围应该是n - (k - path.size(()) +1;

代码实现:

class Solution {
private:
    vector<int>path;
    vector<vector<int>>result;
    void backtracing(int k ,int n ,int sum, int startindex){
        if(sum > n){ //剪枝
            return ;
        }
        if( path.size() == k){
            if(sum == n){
            result.push_back(path);
            return;
            }
        }
        for(int i = startindex; i <= 9-(k - path.size() + 1);i++){//剪枝
            sum += i;
            path.push_back(i);
            backtracing(k, n, sum, i+1);
            sum -= i;
            path.pop_back();
        }
    }
public:
    vector<vector<int>> combinationSum3(int k, int n) {
        result.clear();
        path.clear();
        backtracing(k,n,0,1);
        return result;
    }
};

17.电话号码的字母组合

题目链接:17. 电话号码的字母组合 - 力扣(LeetCode)

解题思路:按照题目要求,我们首先应该建立起对应映射关系,即字符1对应“abc”这种映射关系,这里我们能够采用一个一维数组来进行映射,即索引是字符1,2,3....而里面的值是字符串。然后定义两个全局变量s和result用来收集结果,每遍历到一个字符则将这个字符压入s,若满足终止条件则将s压入result内,然后进行回溯。具体过程,建立映射关系,遍历输入的字符,将该字符单独存储为int型的数,用这个数来取对应的字符串,遍历该字符穿压入s内,若符合终止条件则使用result进行收集结果。

回溯三部曲:

1、递归函数返回类型和传入参数:遍历全局所以没有返回值,而传入参数是题目输入的字符和索引index,index用来记录此时遍历到哪个数字。

2、终止条件:当遍历到叶子节点即当index == digits.size()的时候进行收集结果。

3、单层递归逻辑:首先根据输入字符取出数,然后取出这个数对应的字符,然后使用for循环遍历这个字符,将遍历到的字符压入s内,进行下一层的递归,最后进行回溯。

代码实现:

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 s;
    void backtracing(const string& digits ,int index){
        if(index == digits.size()){
            result.push_back(s);
            return;
        }
        int digit = digits[index] - '0';//取数
        string letters = lettermap[digit];//取字符
        for(int i = 0; i< letters.size();i++){
            s.push_back(letters[i]);
            backtracing(digits,index+1);
            s.pop_back();
        }
    }
public:
    vector<string> letterCombinations(string digits) {
        s.clear();
        result.clear();
        if(digits.size() == 0){
            return result;
        }
        backtracing(digits ,0);
        return result;

    }
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值