【代码随想录】算法训练营day25 | LeetCode216.组合总和III + LeetCode17.电话号码的字母组合

仅用于学习交流,未经许可不可转载。本文转载引用内容仅代表作者本人的观点,与本博客立场无关。

LeetCode216组合总和

代码随想录: 回溯算法——组合总和
力扣216: 组合总和Ⅲ

初印象

  1. 找出所有相加之和为 n 的 k 个数的组合,且满足下列条件:
  • 只使用数字1到9
  • 每个数字 最多使用一次
  • 返回 所有可能的有效组合的列表 。该列表不能包含相同的组合两次,组合可以以任何顺序返回。
  • 2 <= k <= 9;1 <= n <= 60
  1. 回溯函数返回值与输入参数,二维数组vector<vector> result。和77题一样借助一个path。 输入参数n, k
  2. 回溯函数终止条件 path.size=k如果和等于n,返回result
  3. 回溯函数遍历过程LeetCode77题类似,抽象成树形结构,for循环1到9横向遍历,k决定树的深度,子树中一个startindex继续取数。
  4. 剪枝操作:取最小的数后总和大于n。为什么剪枝之前要先把回溯做了? for循环剪枝怎么操作
  5. 回溯,撤销处理结果在代码中如何体现?就是sum-=i;
    path.pop_back();

看视频讲解后的想法

  1. 为什么剪枝之前要先把回溯做了?
  2. 剪枝分别从和的角度、元素个数够不够取的角度剪枝
  3. 从元素个数的角度,for循环剪枝怎么操作?path中已经有path.size个元素,还需要k-path.size个元素,i至多遍历到k-path.size+1。因为是小于等于所以要加一
  4. 从和的角度可以把下列代码放到函数开头
if (sum > tagetsum) return;

实现过程中遇到的问题

剪枝版本

class Solution {
private:
    vector<vector<int>> result;//二维数组存放符合条件的结果的集合
    vector<int> path;//存放符合条件结果
    void backtracking(int targetsum, int k, int sum, int startIndex) {
        //int sum,int startIndex自己从public中传进去
        if (sum > targetsum) {
            return;//总和大于目标和剪枝
        }
        if (path.size() == k) {//size后面加括号,这是终止条件
            if (sum == targetsum) {
                result.push_back(path);
            }
            return;//在这里return,如果path已经达到了k
        }
        for (int i = startIndex; i <= 9 - (k - path.size()) + 1; i++) {//剪枝,不剪枝为i<=9;
            path.push_back(i);
            sum += i;
            backtracking(targetsum, k, sum, i + 1);//这里是i+1,不是startIndex+1
            sum -= i;//回溯,先减去再退栈
            path.pop_back();//这里括号里不能加i
        }
    }
public:
    vector<vector<int>> combinationSum3(int k, int n) {
        result.clear();
        path.clear();
        backtracking(n, k, 0, 1);
        return result;
    }
};
  1. line 5:这个sum和startIndex自己从public部分中传进去相当于全局变量。target和k的顺序不能改变不知道为什么
  2. line 8: 放在开头的总和剪枝
  3. line14:在这里return不要在上面的sum==targetsum里return
  4. line16:剪枝,不剪枝就填i<=9;
  5. line20-21:这俩顺序无所谓,但先减再退栈是好习惯,退栈pop_back不能加操作数
    力扣216ac

LeetCode17电话号码组合

代码随想录: 回溯算法——电话号码的字母组合
力扣17: 电话号码的字母组合

初印象

  1. 给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。
    给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。
    力扣17电话号码组合图片描述

  2. 定义一个二维数组实现数字与字母之间的映射

  3. 题目给了一个string digits,需要一个digitIndex记录树的深度

  4. C++ const关键字用法: 参考Mi ronin的博客——C++ const的用法详解。const修饰函数形参;函数体内不能修改形参a的值。

  5. 将index指向的数字转为int? index用法不太懂,下一层index为什么+1

看视频讲解后的想法

  1. index的用法,表示在digit字符串中已经遍历到的位置。因为是从不同的数字字母映射组合中取数,不用startIndex那种逻辑。
  2. 终止条件是index==digit.size()而不是digit.size()-1即指向最后一位。因为当指向最后一位时,最后一位仍要对应字母仍有处理过程, 不是真正的结束。
  3. int digit=digits[index]-‘0’。从字符串中的数字变成真正的数字。
  4. string letterMap[10]={…}数组中的每个元素是字符串,算是个二维数组。也可以用map来做。
    C++ map关键字用法: 参考不会编程的小猿的博客——C++ 中map详解。map是STL的一个关联容器,以键值对存储的数据,其类型可以自己定义,每个关键字在map中只能出现一次,关键字不能修改,值可以修改
  5. index+1移动处理位置。
  6. 树形结构代码随想录力扣17树形结构

实现过程中遇到的问题

class Solution {
private:
    const string digitsToLetter[10] = {//const表示不可修改
        "",//0
        "",//1
        "abc",//2
        "def",//3
        "ghi",//4
        "jkl",//5
        "mno",//6
        "pqrs",//7
        "tuv",//8
        "wxyz",//9
    };//注意内部格式,使用双引号,中间用逗号隔开
public:
    vector<string> result;
    string s;
    void backtracking(const string&digits,int index) {
    //const string&digits,这个写法需要确认一下
        if (index==digits.size()) {//注意是==
            result.push_back(s);
            return;
        }
        int digit = digits[index] - '0';//获取当前数字,将其转换为真正的数字
        string letters = digitsToLetter[digit];//完成数字与字母之间的转换
        for (int i = 0; i < letters.size(); i++) {//不是小于等于
            s.push_back(letters[i]);
            backtracking(digits, index + 1);//index+1移动到digits下一位
            s.pop_back();
        }
    }
    vector<string> letterCombinations(string digits) {
        s.clear();
        result.clear();
        if (digits.size() == 0) {
            return result;
        }//力扣有空串的测试用例,index初始为0,会不停压入空串
        backtracking(digits, 0);
        return result;
    }
};
  1. line 3:const和string数组的用法
  2. line 15: public由此开始
  3. line18:这个写法需要确认
  4. line20:判断条件是==而非=
  5. line24:字符串数字与真正的数字区别是什么
  6. line26:不是小于等于,size本身是逻辑上从1开始,i从0开始
  7. line35:力扣有空串测试用例

力扣17ac

总结

对回溯算法和组合问题有了更近一步的认识,这两道题总体不难。但是,c++的语法还需熟悉。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
第二十二天的算法训练主要涵盖了Leetcode题目中的三道题目,分别是Leetcode 28 "Find the Index of the First Occurrence in a String",Leetcode 977 "有序数组的平方",和Leetcode 209 "长度最小的子数组"。 首先是Leetcode 28题,题目要求在给定的字符串中找到第一个出现的字符的索引。思路是使用双指针来遍历字符串,一个指向字符串的开头,另一个指向字符串的结尾。通过比较两个指针所指向的字符是否相等来判断是否找到了第一个出现的字符。具体实现的代码如下: ```python def findIndex(self, s: str) -> int: left = 0 right = len(s) - 1 while left <= right: if s[left == s[right]: return left left += 1 right -= 1 return -1 ``` 接下来是Leetcode 977题,题目要求对给定的有序数组中的元素进行平方,并按照非递减的顺序返回结果。这里由于数组已经是有序的,所以可以使用双指针的方法来解决问题。一个指针指向数组的开头,另一个指针指向数组的末尾。通过比较两个指针所指向的元素的绝对值的大小来确定哪个元素的平方应该放在结果数组的末尾。具体实现的代码如下: ```python def sortedSquares(self, nums: List[int]) -> List[int]: left = 0 right = len(nums) - 1 ans = [] while left <= right: if abs(nums[left]) >= abs(nums[right]): ans.append(nums[left ** 2) left += 1 else: ans.append(nums[right ** 2) right -= 1 return ans[::-1] ``` 最后是Leetcode 209题,题目要求在给定的数组中找到长度最小的子数组,

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值