代码随想录训练营day25

本文介绍了如何使用回溯算法解决LeetCode中的两个问题:组合总和III(寻找和为n的k个数组合)和电话号码的字母组合(生成所有可能的数字到字母映射)。作者通过示例和代码解释了回溯法在解决多层循环问题中的应用。
摘要由CSDN通过智能技术生成

第七章 回溯算法part02

1.LeetCode. 组合总和III

1.1题目链接:216.组合总和III

文章讲解:代码随想录
视频讲解:B站卡个视频

1.2思路:本题就是在[1,2,3,4,5,6,7,8,9]这个集合中找到和为n的k个数的组合。相对于77. 组合 (opens new window),无非就是多了一个限制,本题是要找到和为n的k个数的组合,而整个集合已经是固定的了[1,…,9]。想到这一点了,做过77. 组合 (opens new window)之后,本题是简单一些了。本题k相当于树的深度,9(因为整个集合就是9个数)就是树的宽度。例如 k = 2,n = 4的话,就是在集合[1,2,3,4,5,6,7,8,9]中求 k(个数) = 2, n(和) = 4的组合。

选取过程如图:
在这里插入图片描述

1.3附加代码如下所示:

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

    }
};

//简化版
class Solution {
public:
    vector<vector<int>>result;
    vector<int>path;
    // targetSum:目标和,也就是题目中的n。
    // k:题目中要求k个数的集合。
    // sum:已经收集的元素的总和,也就是path里元素的总和。
    // startIndex:下一层for循环搜索的起始位置。
    void bacaktracking(int k,int n,int startindex)
    {
        if(path.size()==k&&n==0)
        {
            result.push_back(path);
            return;// 如果path.size() == k 但sum != targetSum 直接返回
        }
        for(int i=startindex;i<=9;i++)
        {
            path.push_back(i);
            n-=i;
            bacaktracking(k,n,i+1);// 注意i+1调整startIndex
            n+=i;//回溯
            path.pop_back();//回溯
        }
    }
    vector<vector<int>> combinationSum3(int k, int n) {
        bacaktracking(k,n,1);
        return result;

    }
};

2.LeetCode. 电话号码的字母组合

2.1题目链接:17.电话号码的字母组合

文章讲解:代码随想录
视频讲解:B站卡哥视频

2.2思路:理解本题后,要解决如下三个问题:

数字和字母如何映射
两个字母就两个for循环,三个字符我就三个for循环,以此类推,然后发现代码根本写不出来
输入1 * #按键等等异常情况
可以使用map或者定义一个二维数组,例如:string letterMap[10],来做映射,我这里定义一个二维数组,代码如下:

const string letterMap[10] = {
    "", // 0
    "", // 1
    "abc", // 2
    "def", // 3
    "ghi", // 4
    "jkl", // 5
    "mno", // 6
    "pqrs", // 7
    "tuv", // 8
    "wxyz", // 9
};

回溯法来解决n个for循环的问题:例如:输入:“23”,抽象为树形结构,如图所示:
在这里插入图片描述
图中可以看出遍历的深度,就是输入"23"的长度,而叶子节点就是我们要收集的结果,输出[“ad”, “ae”, “af”, “bd”, “be”, “bf”, “cd”, “ce”, “cf”]。

2.3附加代码如下所示:

class Solution {
public:
    //先做字符串的映射
    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 backtracking(const string &digits,int index)
    {
        if(index==digits.size())
        {
            result.push_back(s);
            return;
        }
        int digit=digits[index]-'0';// 将index指向的数字转为int
        string letters=lettermap[digit]; // 取数字对应的字符集
        for(int i=0;i<letters.size();i++)
        {
            s.push_back(letters[i]);//处理遍历字符
            backtracking(digits,index+1); // 递归,注意index+1,一下层要处理下一个数字了
            s.pop_back();//回溯
        }
    }
    vector<string> letterCombinations(string digits) {
        if(digits.size()==0)return result;
        backtracking(digits,0);//注意初始index为什么设为0要考虑好 ,可以带入其中试一试
        return result;

    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值