Day20:代码随想录算法训练营第二十天|回溯算法基础 1.力扣216 组合问题三 2.力扣17 电话号码的字母组合

力扣216 组合问题三

题目描述:
找出所有相加之和为 n 的 k 个数的组合,且满足下列条件:

1.只使用数字1到9
2.每个数字 最多使用一次 

返回 所有可能的有效组合的列表 。该列表不能包含相同的组合两次,组合可以以任何顺序返回。

示例 1: 输入: k = 3, n = 7 输出: [[1,2,4]]

示例 2: 输入: k = 3, n = 9 输出: [[1,2,6], [1,3,5], [2,3,4]]

思路:
和组合问题类似,只不过此时有了一个和为n的条件对所有组合做了一个筛选。也是先抽象为一个多叉树,每一个分支表示从上面节点取了一个数。
如果path记录满了而且sum和目标和相同了,就将path压入结果集,不然直接return。然后在上一次调用中回溯,向其兄弟进行寻找。
同样由于这个多叉树的数值分布是从小到大的,不仅是从上到下,而且是从左到右,当path满了而sum小于等于targetSum的情况已经包含在了终止条件,而当path在宽度遍历时,到某个值满足条件后,其实其后面的值都会时sum偏大,此时就不需要再继续向右遍历和向下递归了。

class Solution {
public:
    vector<vector<int>> result;
    vector<int> path;
    void backTracking(int k, int targetSum, int sum, int startIndex){
        if(path.size() == k){
            if(sum == targetSum){
                result.push_back(path);
            }
            return;
        }
        for(int i = startIndex; i <= 9; i++){
            sum += i;
            path.push_back(i);
            if (sum > targetSum) { // 剪枝操作
            sum -= i; // 剪枝之前先把回溯做了
            path.pop_back(); // 剪枝之前先把回溯做了
            return;
            }
            backTracking(k, targetSum, sum, i + 1);
            path.pop_back();
            sum -= i;//多加了一层回溯,即sum也需要减去先前的值
        }
    }
    vector<vector<int>> combinationSum3(int k, int n) {
        backTracking(k, n, 0, 1);
        return result;
    }
};

力扣17 电话号码的字母组合

题目描述:
给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。

给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。、

在这里插入图片描述示例:

输入:"23"
输出:["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"].

说明:尽管上面的答案是按字典序排列的,但是你可以任意选择答案输出的顺序。

思路:

先构造数字-字符串对应关系,我这里采用的是map,当然用二维数组也可以解决。

之后根据模版,这显然是一个组合的题目,那么首先确定的是终止条件,
我们是在递归过程中保留数据,也就是随着深度的进行,我们存放的path大小会增大,而我们的path大小应该是要等于digits的大小,此时就可以保存结果了。

然后宽度的控制就是数字对应字符集的大小,递归深度就是index控制深度,也是结果的长度。

最后直接套模版就可以写出来了。
代码如下:

class Solution {
private:
    unordered_map<char, string> table;//map构建数字单词表
    //构造为char,string类型,方便后序直接调用
    vector<string> result;
    string path;
   void buildTable() {
    char ch1 = 'a';
    char ch2 = '2';
    for (int i = 2; i <= 9; i++) {
        string temp;
        if (i < 7 || i == 8) {
            for (int j = 0; j < 3; j++) {
                temp += ch1;
                ch1 += 1;
            }
        }
        else {//7,9有四个字符
            for (int j = 0; j < 4; j++) {
                temp += ch1;
                ch1 += 1;
            }
        }
        table.insert(pair<char, string>(ch2, temp));
        ch2 += 1;
    }
}
public:
    void backTracking(string digits, int Index){
        //根据题目很明显可以看出
        //递归深度就是每个组合中的字符数量,也是digits数组的大小
        //当递归深度等于了digits,那么就该收获结果了
        if( Index == digits.size()){
            result.push_back(path);
            return;
        }
       string temp = table.find(digits[Index])->second;
       //获取当前结点的字符集合
        for(int i = 0; i < temp.size() ; i++){
            //按照循环宽度把集合里的字符一个个插入path
            path.push_back(temp[i]);
            //递归的是深度,处理的是下一层的结点,这里可以理解为下一个集合
            //Index加1意思是想下一层找
            backTracking(digits, Index + 1);
            path.pop_back();
        }
    }
    vector<string> letterCombinations(string digits) {
        if(digits.size() == 0){
            return vector<string>{};
        }
        buildTable();
        backTracking(digits, 0);
        return result;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值