【算法总结】——组合型回溯

news/2024/12/1 0:36:57/

文章目录

  • 组合型回溯
    • 例题1——组合
      • 从输入考虑模板
      • 从答案考虑模板
    • 例题2——括号生成
      • 解法一
      • 解法二
  • 剪枝
  • 分析回溯时间复杂度的通用方法

组合型回溯

组合型和子集型之间的差异在哪里呢?
在这里插入图片描述

相比子集问题,组合问题是可以做一些额外的优化的(因为只需要得到某些特定的子集)。


同样是 【选和不选】 以及 【枚举选哪个】 这两种思路。
(具体用哪种思路根据题目特点来做,哪种更好些就选哪种写法)

例题1——组合

https://leetcode.cn/problems/combinations/
在这里插入图片描述

从输入考虑模板

依然是考虑每个数字选或不选,与子集型回溯的差异在于,结果的元素数量必须是k。

class Solution {List<List<Integer>> ans = new ArrayList();List<Integer> t = new ArrayList();public List<List<Integer>> combine(int n, int k) {dfs(1, n, k);return ans;}public void dfs(int i, int n, int k) {if (k == 0) {ans.add(new ArrayList(t));return;}if (i > n) return;dfs(i + 1, n, k);t.add(i);dfs(i + 1, n, k - 1);t.remove(t.size() - 1);}
}

从答案考虑模板

class Solution {List<List<Integer>> ans = new ArrayList();List<Integer> t = new ArrayList();public List<List<Integer>> combine(int n, int k) {dfs(1, n, k);return ans;}public void dfs(int startIndex, int n, int k) {if (k == 0) {ans.add(new ArrayList(t));return;}for (int i = startIndex; i <= n; ++i) {t.add(i);dfs(i + 1, n, k - 1);t.remove(t.size() - 1);}}
}

例题2——括号生成

解法一

选左括号还是右括号

class Solution {List<String> ans = new ArrayList();StringBuilder t = new StringBuilder();public List<String> generateParenthesis(int n) {dfs(n, n);return ans;}public void dfs(int n1, int n2) {if (n1 == 0 && n2 == 0) {ans.add(t.toString());return;}if (n1 > 0) {   // 左括号t.append('(');dfs(n1 - 1, n2);t.deleteCharAt(t.length() - 1);}if (n2 > n1) {  // 右括号t.append(')');dfs(n1, n2 - 1);t.deleteCharAt(t.length() - 1);}}
}

其实回溯里的 if 就相当于是在做剪枝了,所谓的剪枝就是提前过滤掉不合理的答案。

解法二

枚举左括号出现的位置

class Solution {List<String> ans = new ArrayList();List<Integer> pos = new LinkedList();   // 存储左括号的位置public List<String> generateParenthesis(int n) {dfs(0, 0, n);return ans;}public void dfs(int startIndex, int cnt, int n) {if (cnt == n) {char[] chs = new char[2 * n];Arrays.fill(chs, ')');for (int idx: pos) chs[idx] = '(';ans.add(new String(chs));return;}for (int i = startIndex; i <= 2 * cnt; ++i) {pos.add(i);dfs(i + 1, cnt + 1, n);pos.remove(pos.size() - 1);}}
}

这里 for 循环中的 i <= 2 * cnt 相当于剪枝。

剪枝

这里以解法一为例介绍剪枝操作。
由于答案中必须有 k 个元素,因此如果选到 i 的时候,还有 n - i + 1 个元素可供选择,因此如果可供选择的数字已经少于还需要选择的元素,那么就可以不再继续往下尝试了。

class Solution {List<List<Integer>> ans = new ArrayList();List<Integer> t = new ArrayList();public List<List<Integer>> combine(int n, int k) {dfs(1, n, k);return ans;}public void dfs(int i, int n, int k) {if (n - i + 1 < k) return;	// 剪枝if (k == 0) {ans.add(new ArrayList(t));return;}dfs(i + 1, n, k);t.add(i);dfs(i + 1, n, k - 1);t.remove(t.size() - 1);}
}

对于模板二的剪枝方式为:

class Solution {List<List<Integer>> ans = new ArrayList();List<Integer> t = new ArrayList();public List<List<Integer>> combine(int n, int k) {dfs(1, n, k);return ans;}public void dfs(int startIndex, int n, int k) {if (k == 0) {ans.add(new ArrayList(t));return;}for (int i = startIndex; i <= n - k + 1; ++i) {		// 剪枝 i <= n - k + 1t.add(i);dfs(i + 1, n, k - 1);t.remove(t.size() - 1);}}
}

分析回溯时间复杂度的通用方法

时间复杂度是:**叶子的个数** 乘上 **从根到叶子的路径长度**
对于这道题目(例题一)来说,就是 k * C(n, k)

在这里插入图片描述


http://www.ppmy.cn/news/537095.html

相关文章

故障代码表

故障代码 故障描述 处理方法 故障类别 1 电池温度过高 0KW运行 电池故障 2 总电压过低 限流50A 电池故障 3 绝缘一级故障 限流50A 电池故障 4 SOC小于等于10% 限流50A 电池故障 5 单体电压过低 限流50A 电池故障 6 电流过大 限流100A 电池故障 7 …

玉柴spn码故障对照表_故障代码一览表

代码 故障内容 无显示 电源问题;保险丝熔断; X 、 Y 、 Z 信号线连接不良;线控器不良。 E1 线控器与内基板通讯不良。 (定频一拖多机器, 1 个线控器控制多台内机时,其中 1 台内机电源 OFF 或者内机地址重复可导致 E1) E2 室内机地址重复或者 1 个信号线系统超过 49 台内机…

富士通服务器 css灯亮,富士通空调指示灯故障含义-富士通空调指示灯代码

富士通空调运行灯闪烁是什么原因? 富士通立式空调指示灯含义,安卓手机绘画软件推荐 荧光涂鸦 荧光涂鸦是一款拥有绚烂的荧光色彩,随意自如的涂鸦方式的安卓手机绘画软件。简单的操作,细腻的效果,荧光涂鸦可以被称为涂鸦爱好者手机必备软件了。 光涂鸦这个软件操作十分简单…

lg空调代码大全解决_lg空调故障代码是什么意思 lg空调故障代码大全【详解】...

在使用空调的过程中会常遇到一些故障&#xff0c;出现故障时显示屏上会显示一些代码&#xff0c;找出对应的代码在空调故障代码网进行查阅就可以清楚知道空调的故障原因在哪里。然后再去寻找专业的维修人员进行维修&#xff0c;这样就简单很多&#xff0c;同时也更加节省时间。…

反射(reflection)详细讲解

反射(reflection) 反射机制允许程序在执行期借助于ReflectionAPI取得任何类的内部信息&#xff08;比如成员变量&#xff0c;构造器&#xff0c;成员方法等等&#xff09;&#xff0c;并能操作对象的属性及方法。反射在设计模式和框架底层都会用到加载完类之后&#xff0c;在堆…

TreeMap数据结构及源码解析.跟学黑马

TreeMap数据结构及源码解析 1.TreeMap的特点2.TreeMap的数据结构2.1二叉查找树2.1.1二叉查找树的定义2.1.2二叉查找树的查找操作 2.2平衡二叉树2.2.1平衡二叉树的定义2.2.2平衡二叉树的旋转 2.3红黑树2.3.1红黑树的定义 2.TreeMap的源码分析2.1get()获取方法分析2.2put()添加方…

理解家庭宽带上网通信过程

理解家庭宽带上网通信过程

ADSL、宽带上网、光缆和拨号上网之间的区别?

拔号上网,是用MODEN接电话线,拔一个特定号码, 能接入到互联网&#xff0c;此时电话处于占线状态&#xff0c;网速 56Kbps左右。[基本淘汰了 ] 宽带上网&#xff0c;包括了ADSL、光纤等网速较快的上网方式&#xff0c;是个泛指。 ADSL (非对称数字用户环路)基于电话线上的宽带&…