LeetCode刷题笔记【19】:回溯专题-2(组合总和III、电话号码的字母组合)

前置知识

参考前文

参考文章:
LeetCode刷题笔记【18】:回溯专题-1(回溯算法基础知识、用回溯算法解决组合问题)

216.组合总和III

题目描述

在这里插入图片描述

LeetCode链接:https://leetcode.cn/problems/combination-sum-iii/description/

解题思路

// 思路: 用回溯算法, 过程中记录当前使用了几个数字, 以及当前的sum和

代码

class Solution {
private:
    vector<vector<int>> ans;
    vector<int> path;
    int sum;
public:
    void helper(int k, int n, int curNum, int numNum){
        if(numNum==k){
            if(sum==n){
                ans.push_back(path);
            }
            return;
        }
        for(int i=curNum; i<=9; ++i){
            path.push_back(i);
            sum += i;
            helper(k, n, i+1, numNum+1);
            path.pop_back();
            sum -= i;
        }
        return;
    }
    vector<vector<int>> combinationSum3(int k, int n) {
        helper(k, n, 1, 0);
        return ans;
    }
};

改进

① 函数命名用backtracking
② 不用记录numNum的, 可以用path.size()
③ 可以不用sum, 每一步用n-i即可
④ 进行剪枝(当之前sum>n, 或者现在n<0时, 直接return)

class Solution {
private:
    vector<vector<int>> ans;
    vector<int> path;
public:
    void backTracking(int k, int n, int curNum){
    	if(n<0) return;
        if(path.size()==k){
            if(n==0){
                ans.push_back(path);
            }
            return;
        }
        for(int i=curNum; i<=9; ++i){
            path.push_back(i);
            backTracking(k, n-i, i+1);
            path.pop_back();
        }
        return;
    }
    vector<vector<int>> combinationSum3(int k, int n) {
        backTracking(k, n, 1);
        return ans;
    }
};

17.电话号码的字母组合

题目描述

在这里插入图片描述

LeetCode链接:https://leetcode.cn/problems/letter-combinations-of-a-phone-number/description/

解题思路

思路: 用回溯算法, 每一位数字是一层回溯
unordered_map<char,string>存储电话按键符号和对应的string
每一层回溯函数的参数记录自己当前操作的是第几位数字

代码

class Solution {
    unordered_map<char,string> phoneMap{
        {'2', "abc"},
        {'3', "def"},
        {'4', "ghi"},
        {'5', "jkl"},
        {'6', "mno"},
        {'7', "pqrs"},
        {'8', "tuv"},
        {'9', "wxyz"}
    };
    vector<string> ans;
    string cur;
public:
    void backtrack(const string& digits, int vec){
        if(cur.size()==digits.size()){
            ans.push_back(cur);
            return;
        }
        string letters = phoneMap[digits[vec]];
        for(int i=0; i<letters.size(); ++i){
            cur.push_back(letters[i]);
            backtrack(digits, vec+1);
            cur.pop_back();
        }
        return;
    }
    vector<string> letterCombinations(string digits) {
        if(digits.size()==0)
            return ans;
        backtrack(digits, 0);
        return ans;
    }
};

总结

今天的两道题虽然都套用了昨天说到的"回溯模板", 但是具体的操作有所区别, 我们可以对比总结为:

当需要"每个数字至多使用一次"的时候, 就需要每次从i=index开始循环;
当"简单遍历循环所有可能"的时候, 需要i=0开始循环.

同时在使用回溯算法的过程中, 有一些trick:
① 对于过程中使用的anscur, 虽然也可以以引用的方式写在回溯函数参数里面, 但是写在private部分, 可以让整体更为清爽;
② 固定一些函数和参数的命名, 可以更好地帮助自己理清回溯的思路, 如backtrack, ans, path, index;
③ 过程中无需改变的量, 可以设置为const.

本文参考:
组合总和III
电话号码的字母组合

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值