首页 > 编程语言 >代码随想录算法训练营第 22 天 |LeetCode77. 组合 LeetCode 216.组合总和III LeetCode17.电话号码的字母组合

代码随想录算法训练营第 22 天 |LeetCode77. 组合 LeetCode 216.组合总和III LeetCode17.电话号码的字母组合

时间:2024-07-25 12:25:24浏览次数:12  
标签:digits 组合 int res 随想录 vector 字母组合 path

代码随想录算法训练营

Day22 代码随想录算法训练营第 22 天 |LeetCode77. 组合 LeetCode 216.组合总和III LeetCode17.电话号码的字母组合


目录


前言

LeetCode77. 组合

讲解文档

LeetCode216.组合总和III

讲解文档

LeetCode17.电话号码的字母组合

讲解文档


一、基础

1、回溯可以解决什么问题

组合问题:N个数里面按一定规则找出k个数的集合
切割问题:一个字符串按一定规则有几种切割方式
子集问题:一个N个数的集合里有多少符合条件的子集
排列问题:N个数按一定规则排列,有几种排列方式
棋盘问题:N皇后,解数独

2、回溯法

(1)回溯法解决的问题都抽象为树形结构,是一棵高度有限的树(N叉树)
(2)回溯法解决的都是在集合中递归查找子集,集合的大小就构成了树的宽度,递归的深度就构成了树的深度。
(3)模板

void backtracking(参数) {
    if (终止条件) {
        存放结果;
        return;
    }

    for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {
        处理节点;
        backtracking(路径,选择列表); // 递归
        回溯,撤销处理结果
    }
}

二、LeetCode77. 组合

1.题目链接

LeetCode77. 组合

2.思路

(1)参数:start是每一层搜索起始位置
(2)边界:组合凑够k个元素,存答案,返回
(3)单层递归:
从start开始这层的搜索
1)当前点存入组合
2)递归下一层
3)回溯,将当前点弹出

3.题解

class Solution {
public:
    
    void add_path(int n,int k,int start,vector<vector<int>>& res,vector<int> &path)
    {
        if(path.size()==k)
        {
            res.push_back(path);
            return;
        }
        for(int i=start;i<=n;i++)
        {
            path.push_back(i);
            add_path(n,k,i+1, res,path);
            path.pop_back();
        }
    }
    vector<vector<int>> combine(int n, int k) {
        vector<vector<int>> res;
        vector<int> path;
        add_path(n,k,1,res,path);
        return res;

    }
};

(4)剪枝优化

for (int i = startIndex; i <= n - (k - path.size()) + 1; i++) // i为本次搜索的起始位置

如果i太靠后,组合凑不出k个数

三、LeetCode 216.组合总和III

1.题目链接

LeetCode216.组合总和III

2.思路

和上面模板题差不多,区别有三个
(1)类成员加一个sum
(2)边界条件:长度为K,但是要比较和是不是n
(3)单层递归时,每轮循环sum加当前数字,回溯时减掉

3.题解

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

四、LeetCode17.电话号码的字母组合

1.题目链接

LeetCode17.电话号码的字母组合

2.思路

(1)数字和字母的对应关系:

  • 我选择用字符串数组映射,下标表示数字,数组元素为数字对应的字符串(有点哈希表的感觉)
  • 为了让下标2对应"abc",我将下标0和1对应成空字符串,从下标2开始映射
    (2)存放答案:
    用字符串数组存放最后的答案,用字符串存放每一条路径(组合)
    (把模板里面数组存放路径改成字符串存放路径)
    (3)递归
    1)返回值和参数
  • 返回值选择void,写递归容易
  • 参数包括:
    • 表示数字的字符串digits;
    • index表示本轮讨论digits当中下标为index的元素;
    • n是digits的长度,没有也行,但是为了避免重复的调用digits.size()浪费时间,我还是加上了

2)边界条件:路径长度(组合大小)等于digits,将组合存入答案

3)单层递归
① 获取当前讨论的数字:从digits取出,并转换成数字
② 求当前讨论的数字映射的字符串长度,即为len
③ for循环讨论这个数字映射的字符串中哪一个字符应该放进组合:

将字符加入路径
递归调用求解digits里面下一个数字(index+1)
将讨论过的字符取出

3.题解

class Solution {
public:
    vector<string> s = {"",    "",    "abc",  "def", "ghi",
                        "jkl", "mno", "pqrs", "tuv", "wxyz"};
    vector<string> res;
    string path;
    void func(string digits, int index, int n) {
        if (path.size() == n) {
            res.push_back(path);
            return;
        }
        int number = digits[index] - '0'; // 现在讨论的是字符串中那个数字
        int len = s[number].size(); // 现在讨论的数字对应字符串有多少个字符
        for (int i = 0; i < len; i++) {
            path += s[number][i];
            func(digits, index + 1, n);
            path.pop_back();
        }
    }
    vector<string> letterCombinations(string digits) {
        int n = digits.size();
        if (n == 0)
            return res;
        func(digits, 0, n);
        return res;
    }
};

标签:digits,组合,int,res,随想录,vector,字母组合,path
From: https://blog.csdn.net/2301_79647020/article/details/140653766

相关文章

  • 代码随想录算法训练营第二十二天|回溯算法part01
    第77题.组合在单个集合1-n中,寻找所有个数为k的组合。和所有递归一样,都有三部曲。确定参数与返回值确定终止条件单层逻辑首先,回溯算法的返回值一般是void,参数依照题目要求而增加,在这一题中,参数有n,k还有startIndex。终止条件是path的size等于k,将path存放在result中。......
  • 条件组合组件--vue3版
    参考手把手教你写一个条件组合组件此随笔是借鉴以上写的vue版,记录一下组件前期准备1.vue3的全套工具2.element-plus3.lodash数据结构主要是嵌套结构关键点在RelationGroup组件内引用本身,注意key值,不能用i,不然删除操作,会从最后删起组件结构主要是这3个文件引用......
  • 代码随想录算法训练营第43天 | 动态规划7:买卖股票
    121.买卖股票的最佳时机https://leetcode.cn/problems/best-time-to-buy-and-sell-stock/description/代码随想录https://programmercarl.com/0121.买卖股票的最佳时机.html#算法公开课and-sell-stock/description/122.买卖股票的最佳时机IIhttps://leetcode.cn/problems/be......
  • 代码随想录算法训练营第42天 | 动态规划7:打家劫舍入门
    打家劫舍https://leetcode.cn/problems/house-robber/description/代码随想录https://programmercarl.com/0198.打家劫舍.html打家劫舍-环形https://leetcode.cn/problems/house-robber-ii/description/代码随想录https://programmercarl.com/0213.打家劫舍II.html#思路......
  • 设计模式总结:适配器、桥接、组合和迭代器模式
    在之前的对话中,我们讨论了五种常见的Java设计模式:单例、工厂、策略、装饰器和观察者模式。现在,让我们继续探索其他四种设计模式:适配器、桥接、组合和迭代器模式。适配器模式概念:适配器模式是一种结构型设计模式,用于将一个类的接口转换为另一个类期望的接口。适配器模式......
  • 梯度方法求解最优投资组合问题 (二次规划问题)
    优化程序分析师的目标是帮助投资者“做最好的事”。他们的共同目标应该是制定一套投资策略,为投资者提供最大可能的效用。在某些情况下,这可以形式化为一个涉及目标函数最大化的问题(例如投资者的投资组合的效用),该问题受到一个或多个约束(例如投资者的财富水平所施加的约束)。在投......
  • 代码随想录 day34 不同路径 | 不同路径 II
    不同路径不同路径解题思路通过动态规划,先将第一行和第一列设为1,目的是初始化dp,这样设置的理由是这些格子只有一条路能达到,接着就是遍历整个路径,每个格子所包含的路径和为其左边和上边的路径数之和,随后在目的地格子得到值。知识点动态规划心得没想到初始化的方式,导致没有实......
  • 【Gin】架构的精妙编织:Gin框架中组合模式的革新实践与技术深度解析(下)
    【Gin】架构的精妙编织:Gin框架中组合模式的革新实践与技术深度解析(下)大家好我是寸铁......
  • 「代码随想录算法训练营」第十九天 | 回溯算法 part01
    回溯算法模板voidbacktracking(参数){if(终止条件){存放结果;return;}for(选择:本层集合中元素(树中节点孩子的数量就是集合的大小)){处理节点;backtracking(路径,选择列表);//递归回溯,撤销处理结果}}......
  • 代码随想录算法训练营第八天|● 344.反转字符串● 541. 反转字符串II● 卡码网:54.替换
    题目:344.反转字符串编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 s 的形式给出。不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用O(1)的额外空间解决这一问题。示例1:输入:s=["h","e","l","l","o"]输出:["o","l","l","e",&......