代码随想录算法训练营第二十五天 | LeetCode 216. 组合总和 III、17. 电话号码的字母组合

简介: 代码随想录算法训练营第二十五天 | LeetCode 216. 组合总和 III、17. 电话号码的字母组合

1. LeetCode 216. 组合总和 III

1.1 思路

  1. 这题与77.组合的区别在于给我们的是一个和为n的限制,集合固定在[1,9]。
  2. 思路和77.组合大概相同,同样是通过回溯算法的递归帮我们控制for循环的嵌套层数,也是抽象成一个树形结构。这里的取数之后,剩下的集合就不包括前面取过的数,比如取1后剩下集合[2,9],取2后剩下集合[3,9],为什么没了1呢?因为我们求得是组合不是排列。我们如何控制这个集合范围呢?通过startIndex来控制。而我们的树的深度是由k来控制的,取几个元素就是递归几层。树的宽度是由最初的集合大小9来控制的。
  3. 定义全局变量path来收集结果,然后result放入多个path结果,因为结果可能不止一个
  4. 回溯函数的参数和返回值:返回值void,参数targetSum也就是n,k,sum收集路径已有的和,startIndex
  5. 终止条件:如果path.size()==k说明已经取够数作为组合了,因为结果在叶子节点上,那么可以判断sum是否等于targetSum,等于说明path路径符合就可以把其加入result然后返回了
  6. 单层搜索的逻辑:i从startIndex开始,范围为i<=9,取了数i之后就可以用sum加上。然后把数i加入到path中。然后就回溯了,把参数传入,其中的startIndex为i+1。然后是回溯的过程,要把sum减去数i,然后path弹出数i,比方说这一层已经取过12了,如何取到13呢?就是先把2弹出,再去取3,因此我们要先把数2弹出才可

1.2 代码

//
class Solution {
    List<List<Integer>> result=new ArrayList<>();
    LinkedList<Integer> path=new LinkedList<>();
    public List<List<Integer>> combinationSum3(int k, int n) {
        backtracking(k,n,1,0);
        return result;
    }
    public void backtracking(int k,int n,int startIndex,int sum){
        if(path.size()==k){
            if(sum==n){
                result.add(new ArrayList(path));
            }
            return;
        }
        for(int i=startIndex;i<=9;i++){
            path.add(i);
            sum+=i;
            backtracking(k,n,i+1,sum);
            path.removeLast();
            sum-=i;
        }
    }
}

1.3 剪枝优化思路

  1. 在每一层中如果此时sum已经大于targetSum就没有继续递归取数的必要了,已经不可能符合,因此可以直接return
  2. 然后是for循环的优化:当前递归里组合已经有path.size()个元素了,题目需要k个,就还需要k-path.size()个,那我们还需要取的元素至多可以让你从9-(k-path.size())+1个位置上开始取了,+1是为了把下标补齐。比如我们此时要取k=3个数,已经取了1个了,还剩2个,那么此时至多可以从9-(3-1)+1=8,这个位置开始取[8,9]还剩下2个元素。那么9-(k-path.size())+1这个就是作为i的范围了

1.4 代码

//
class Solution {
  List<List<Integer>> result = new ArrayList<>();
  LinkedList<Integer> path = new LinkedList<>();
  public List<List<Integer>> combinationSum3(int k, int n) {
    backTracking(n, k, 1, 0);
    return result;
  }
  private void backTracking(int targetSum, int k, int startIndex, int sum) {
    // 减枝
    if (sum > targetSum) {
      return;
    }
    if (path.size() == k) {
      if (sum == targetSum) result.add(new ArrayList<>(path));
      return;
    }
    // 减枝 9 - (k - path.size()) + 1
    for (int i = startIndex; i <= 9 - (k - path.size()) + 1; i++) {
      path.add(i);
      sum += i;
      backTracking(targetSum, k, i + 1, sum);
      //回溯
      path.removeLast();
      //回溯
      sum -= i;
    }
  }
}

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

2.1 思路

  1. 首先要解决的问题是题目映射的问题,我们输入的虽然是字符串,但这个字符串是一个数字,用这个数字到字符串要做个映射,我们可以用map也可以用二维数组做映射,初始化数组letterMap长度为10,下标2到9这8个位置就是对应的字符串(字符串本身也是个数组,因此是二维的)。
  2. 我们可以通过for循环来遍历,但由于给的数字长度是不确定的,用几个for循环就不好控制了,就可以通过回溯算法的递归来控制for循环的嵌套次数
  3. 因此我们可以抽象为一个树形结构,树的深度就是数字的长度,树的宽度是由每一个数字所对应的字母的长度来控制的。结果就是都在叶子节点上,也就是递归结束的地方
  4. 定义两个全局变量,str用来收集单个结果,result是个字符串数组,用来收集所有结果
  5. 回溯函数的参数和返回值:返回值void,参数就是数字字符串digits,index表示我传入的字符串遍历到哪里了。为什么这题不像上面的一样弄个startIndex呢?因为这题我们不是在同一个集合里求元素,而是多个的,因此不需要控制集合里我们遍历过哪些元素。
  6. 终止条件:当index==digits.length()时即这个数字字符串的最后一位的下一位,如果是最后一位的话我们还应该要进行处理的,所以是最后一位的下一位。然后就收获叶子节点的结果,result.add(str.toString())然后return。
  7. 单层搜索的逻辑:int digit=digits[index]-'0',因为本身是个字符,因此减去字符0才变成一个数字,然后获取到字符串就是String letter=letterMap[digit],然后在for循环里取字符,就正常的遍历顺序,然后要在str里存放我们取的字符,str.append(letter.charAt(i)),然后是下一层递归backtracking(digits,index+1),然后就是回溯了,要把当前位置的元素弹出,str.deleteCharAt(str.length()-1),因为我们要继续要右边取数遍历
  8. 本题不需要剪纸,因为要的就是所有可能的组合

2.2 代码

//
class Solution {
    //设置全局列表存储最后的结果
    List<String> list = new ArrayList<>();
    public List<String> letterCombinations(String digits) {
        if (digits == null || digits.length() == 0) {
            return list;
        }
        //初始对应所有的数字,为了直接对应2-9,新增了两个无效的字符串""
        String[] numString = {"", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"};
        //迭代处理
        backTracking(digits, numString, 0);
        return list;
    }
    //每次迭代获取一个字符串,所以会设计大量的字符串拼接,所以这里选择更为高效的 StringBuild
    StringBuilder temp = new StringBuilder();
    //比如digits如果为"23",num 为0,则str表示2对应的 abc
    public void backTracking(String digits, String[] numString, int num) {
        //遍历全部一次记录一次得到的字符串
        if (num == digits.length()) {
            list.add(temp.toString());
            return;
        }
        //str 表示当前num对应的字符串
        String str = numString[digits.charAt(num) - '0'];
        for (int i = 0; i < str.length(); i++) {
            temp.append(str.charAt(i));
            //c
            backTracking(digits, numString, num + 1);
            //剔除末尾的继续尝试
            temp.deleteCharAt(temp.length() - 1);
        }
    }
}
相关文章
|
21天前
|
存储 算法 程序员
C 语言递归算法:以简洁代码驾驭复杂逻辑
C语言递归算法简介:通过简洁的代码实现复杂的逻辑处理,递归函数自我调用解决分层问题,高效而优雅。适用于树形结构遍历、数学计算等领域。
|
21天前
|
并行计算 算法 测试技术
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面,旨在通过综合策略提升程序性能,满足实际需求。
50 1
|
1月前
|
存储 缓存 算法
通过优化算法和代码结构来提升易语言程序的执行效率
通过优化算法和代码结构来提升易语言程序的执行效率
|
1月前
|
算法
分享一些提高二叉树遍历算法效率的代码示例
这只是简单的示例代码,实际应用中可能还需要根据具体需求进行更多的优化和处理。你可以根据自己的需求对代码进行修改和扩展。
|
1月前
|
存储 算法 Java
leetcode算法题-有效的括号(简单)
【11月更文挑战第5天】本文介绍了 LeetCode 上“有效的括号”这道题的解法。题目要求判断一个只包含括号字符的字符串是否有效。有效字符串需满足左括号必须用相同类型的右括号闭合,并且左括号必须以正确的顺序闭合。解题思路是使用栈数据结构,遍历字符串时将左括号压入栈中,遇到右括号时检查栈顶元素是否匹配。最后根据栈是否为空来判断字符串中的括号是否有效。示例代码包括 Python 和 Java 版本。
|
1月前
|
分布式计算 Java 开发工具
阿里云MaxCompute-XGBoost on Spark 极限梯度提升算法的分布式训练与模型持久化oss的实现与代码浅析
本文介绍了XGBoost在MaxCompute+OSS架构下模型持久化遇到的问题及其解决方案。首先简要介绍了XGBoost的特点和应用场景,随后详细描述了客户在将XGBoost on Spark任务从HDFS迁移到OSS时遇到的异常情况。通过分析异常堆栈和源代码,发现使用的`nativeBooster.saveModel`方法不支持OSS路径,而使用`write.overwrite().save`方法则能成功保存模型。最后提供了完整的Scala代码示例、Maven配置和提交命令,帮助用户顺利迁移模型存储路径。
|
16天前
|
算法
基于WOA算法的SVDD参数寻优matlab仿真
该程序利用鲸鱼优化算法(WOA)对支持向量数据描述(SVDD)模型的参数进行优化,以提高数据分类的准确性。通过MATLAB2022A实现,展示了不同信噪比(SNR)下模型的分类误差。WOA通过模拟鲸鱼捕食行为,动态调整SVDD参数,如惩罚因子C和核函数参数γ,以寻找最优参数组合,增强模型的鲁棒性和泛化能力。
|
22天前
|
机器学习/深度学习 算法 Serverless
基于WOA-SVM的乳腺癌数据分类识别算法matlab仿真,对比BP神经网络和SVM
本项目利用鲸鱼优化算法(WOA)优化支持向量机(SVM)参数,针对乳腺癌早期诊断问题,通过MATLAB 2022a实现。核心代码包括参数初始化、目标函数计算、位置更新等步骤,并附有详细中文注释及操作视频。实验结果显示,WOA-SVM在提高分类精度和泛化能力方面表现出色,为乳腺癌的早期诊断提供了有效的技术支持。
|
2天前
|
供应链 算法 调度
排队算法的matlab仿真,带GUI界面
该程序使用MATLAB 2022A版本实现排队算法的仿真,并带有GUI界面。程序支持单队列单服务台、单队列多服务台和多队列多服务台三种排队方式。核心函数`func_mms2`通过模拟到达时间和服务时间,计算阻塞率和利用率。排队论研究系统中顾客和服务台的交互行为,广泛应用于通信网络、生产调度和服务行业等领域,旨在优化系统性能,减少等待时间,提高资源利用率。
|
10天前
|
存储 算法
基于HMM隐马尔可夫模型的金融数据预测算法matlab仿真
本项目基于HMM模型实现金融数据预测,包括模型训练与预测两部分。在MATLAB2022A上运行,通过计算状态转移和观测概率预测未来值,并绘制了预测值、真实值及预测误差的对比图。HMM模型适用于金融市场的时间序列分析,能够有效捕捉隐藏状态及其转换规律,为金融预测提供有力工具。
下一篇
DataWorks