当前位置: 首页 > news >正文

Day22--回溯--77. 组合,216. 组合总和 III,17. 电话号码的字母组合

Day22–回溯–77. 组合,216. 组合总和 III,17. 电话号码的字母组合

回溯理论知识

《代码随想录》:

  • 什么是回溯法?
    • 回溯法也可以叫做回溯搜索法,它是一种搜索的方式。
    • 回溯是递归的副产品,只要有递归就会有回溯。
    • 所以以下讲解中,回溯函数也就是递归函数,指的都是一个函数。
  • 回溯法的效率?
    • 回溯法的性能如何呢,这里要和大家说清楚了,虽然回溯法很难,很不好理解,但是回溯法并不是什么高效的算法
    • 因为回溯的本质是穷举,穷举所有可能,然后选出我们想要的答案,如果想让回溯法高效一些,可以加一些剪枝的操作,但也改不了回溯法就是穷举的本质。
  • 那么既然回溯法并不高效为什么还要用它呢?
    • 因为没得选,一些问题能暴力搜出来就不错了,撑死了再剪枝一下,还没有更高效的解法。
  • 回溯法,一般可以解决如下几种问题:
    • 组合问题:N个数里面按一定规则找出k个数的集合
    • 切割问题:一个字符串按一定规则有几种切割方式
    • 子集问题:一个N个数的集合里有多少符合条件的子集
    • 排列问题:N个数按一定规则全排列,有几种排列方式
    • 棋盘问题:N皇后,解数独等等
  • 如何理解回溯法?
    • 回溯法解决的问题都可以抽象为树形结构,是的,我指的是所有回溯法的问题都可以抽象为树形结构!
    • 因为回溯法解决的都是在集合中递归查找子集,集合的大小就构成了树的宽度,递归的深度就构成了树的深度
    • 递归就要有终止条件,所以必然是一棵高度有限的树(N叉树)。

摘抄:大家可以从图中看出for循环可以理解是横向遍历,backtracking(递归)就是纵向遍历,这样就把这棵树全遍历完了,一般来说,搜索叶子节点就是找的其中一个结果了。

// 回溯算法模板框架
void backtracking(参数) {if (终止条件) {存放结果;return;}for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {处理节点;backtracking(路径,选择列表); // 递归回溯,撤销处理结果}
}

77. 组合

思路:

回溯法backtracking。时间复杂度: O(n * 2^n)

// 递归法,使用startIndex作为重要递归参数
class Solution {List<List<Integer>> res = new ArrayList<>();List<Integer> path = new ArrayList<>();public List<List<Integer>> combine(int n, int k) {backtracking(n, k, 1);return res;}private void backtracking(int n, int k, int startIndex) {// 当够k个了,就加到resif (path.size() == k) {res.add(new ArrayList(path));return;}for (int i = startIndex; i <= n; i++) {// path加入本层元素path.add(i);// 下一层从i+1开始backtracking(n, k, i + 1);path.remove(path.size() - 1);}}
}

思路:
剪枝优化

// 递归法,使用startIndex作为重要递归参数
class Solution {List<List<Integer>> res = new ArrayList<>();List<Integer> path = new ArrayList<>();public List<List<Integer>> combine(int n, int k) {backtracking(n, k, 1);return res;}private void backtracking(int n, int k, int startIndex) {// 剪枝;剩余的元素(n - startIndex + 1)加上已有的元素path.size()都不够k个了,就返回if ((n - startIndex + 1) + path.size() < k) {return;}// 当够k个了,就加到resif (path.size() == k) {res.add(new ArrayList(path));return;}for (int i = startIndex; i <= n; i++) {// path加入本层元素path.add(i);// 下一层从i+1开始backtracking(n, k, i + 1);path.remove(path.size() - 1);}}
}

216. 组合总和 III

题目翻译:k个数相加等于n,注意数字只能1->9不是1->n

思路:

递归法。使用startIndex和target作为重要递归参数

  • 写在递归函数中的,+1或者-1,就是自带“回溯”。
  • 先手动+1,递归后再手动-1的效果是一样的
// 递归法。使用startIndex和target作为重要递归参数
class Solution {List<List<Integer>> res = new ArrayList<>();List<Integer> path = new ArrayList<>();public List<List<Integer>> combinationSum3(int k, int n) {backtracking(k, 1, n);return res;}private void backtracking(int k, int startIndex, int target) {// 剪枝,不然会超时。// 当target<0,证明和过大了,当path.size()超过了k个,证明和过小了(需要的数字过多)if (target < 0 || path.size() > k) {return;}// 个数够了 且 target==0if (path.size() == k && target == 0) {res.add(new ArrayList(path));}// 注意这里是小于9不是小于nfor (int i = startIndex; i <= 9; i++) {path.add(i);// 下一层遍历从i+1开始,同时,仍需要的target,要减去本层已有的i// 写在递归函数中的,+1/-1,就是自带“回溯”。// 先手动+1,递归后再手动-1的效果是一样的backtracking(k, i + 1, target - i);path.remove(path.size() - 1);}}
}

17. 电话号码的字母组合

思路:

组合问题。就是要将按键转为字符数组。比如按键”23“,就是['a','b','c']和['d','e','f']的组合问题。

class Solution {// 结果集List<String> res = new ArrayList<>();// 路径上的元素集StringBuilder path = new StringBuilder();public List<String> letterCombinations(String digits) {backtracking(digits, 0);return res;}private void backtracking(String digits, int index) {// 如果index=n,证明越界了,已经遍历完了if (index == digits.length()) {return;}// 获取当前循环的按键所拥有的字母char[] ch = getChars(digits.charAt(index));// 遍历这个按键的字母// 如果遍历到了最后一个按键,要做收尾工作,把path转为字符串记录到resif (index == digits.length() - 1) {for (int i = 0; i < ch.length; i++) {path.append(ch[i]);res.add(new String(path));path.deleteCharAt(path.length() - 1);}} else {// 如果不是最后一个按键,递归遍历下一个按键(index+1)for (int i = 0; i < ch.length; i++) {path.append(ch[i]);backtracking(digits, index + 1);// 记得path要做回溯操作path.deleteCharAt(path.length() - 1);}}}// 获取这个按键所拥有的字母private char[] getChars(char number) {switch (number) {case '2': {return new char[] { 'a', 'b', 'c' };}case '3': {return new char[] { 'd', 'e', 'f' };}case '4': {return new char[] { 'g', 'h', 'i' };}case '5': {return new char[] { 'j', 'k', 'l' };}case '6': {return new char[] { 'm', 'n', 'o' };}case '7': {return new char[] { 'p', 'q', 'r', 's' };}case '8': {return new char[] { 't', 'u', 'v' };}case '9': {return new char[] { 'w', 'x', 'y', 'z' };}}return null;}
}

其中,获取这个按键所拥有的字母可以做优化。遍历到了最底层,拼接的时机可以优化。

class Solution {// 结果集List<String> res = new ArrayList<>();// 路径上的元素集StringBuilder path = new StringBuilder();// 按键所拥有的字母,其中"0","1"是空串String[] numString = { "", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz" };public List<String> letterCombinations(String digits) {if (digits == null || digits.length() == 0) {return res;}backtracking(digits, 0);return res;}private void backtracking(String digits, int index) {// 如果index=n,证明越界了,已经遍历完了if (index == digits.length()) {// 要做收尾工作,把path转为字符串记录到resres.add(new String(path));return;}// 获取当前循环的按键所拥有的字母String letters = numString[digits.charAt(index) - '0'];// 遍历这个按键的字母for (int i = 0; i < letters.length(); i++) {path.append(letters.charAt(i));// 如果不是最后一个按键,递归遍历下一个按键(index+1)backtracking(digits, index + 1);// 记得path要做回溯操作path.deleteCharAt(path.length() - 1);}}}
http://www.xdnf.cn/news/1236061.html

相关文章:

  • Kafka 是什么?
  • 《汇编语言:基于X86处理器》第11章 MS-Windows编程(3)
  • 【stm32】按键控制LED以及光敏传感器控制蜂鸣器
  • OSPF知识点整理
  • 实战《从0开始使用SwiftUI搭建记账软件》- 2、SwiftUI 知识点详解与使用场景
  • 6.1、Redis多级缓存原理和优化、Redis部分参数优化调整
  • 【超分辨率专题】PiSA-SR:单步Diff超分新突破,即快又好,还能在线调参
  • Linux 摄像头实时抓取:V4L2、FFmpeg 与 GStreamer 全面讲解
  • python工具方法51 视频数据的扩充(翻转、resize、crop、re_fps)
  • Transformer模型用于MT信号相关性预测与分析
  • 《深入浅出RabbitMQ:从零基础到面试通关》
  • 渗透作业4
  • wordpress登陆前登陆后显示不同的顶部菜单
  • 数据结构代码
  • 08.Redis 持久化
  • AOP动态代理
  • #C语言——刷题攻略:牛客编程入门训练(四):运算
  • 大屏项目展示
  • 面向智能体的上下文工程:策略、实现与 LangGraph 实践
  • 09.Redis 常用命令
  • STM32-ESP8266通过MQTT与阿里云通讯
  • Coze 打通飞书多维表格,实现数据增删改查操作实战详解
  • Java线程安全类设计思路总结
  • kafka 是一个怎样的系统?是消息队列(MQ)还是一个分布式流处理平台?
  • RabbitMQ死信队列与消息幂等性实践指南
  • Rust:如何访问 *.ini 配置文件?
  • 关于车位引导及汽车乘梯解决方案的专业性、系统性、可落地性强的综合设计方案与技术实现说明,旨在为现代智慧停车楼提供高效、安全、智能的停车体验。
  • Noob靶场练习
  • 【python实用小脚本-169】『Python』所见即所得 Markdown 编辑器:写完即出网页预览——告别“写完→保存→刷新”三连
  • Rustdesk中继服务器搭建(windows 服务器)