[豪の算法奇妙冒险] 代码随想录算法训练营第二十二天 | 77-组合、216-组合总和Ⅱ、17-电话号码的字母组合
代码随想录算法训练营第二十二天 | 77-组合、216-组合总和Ⅱ、17-电话号码的字母组合
LeetCode77 组合
题目链接:https://leetcode.cn/problems/combinations/
文章讲解:https://programmercarl.com/0077.组合.html
视频讲解:https://www.bilibili.com/video/BV1ti4y1L7cv/?vd_source=b989f2b109eb3b17e8178154a7de7a51
start用来记录下一轮回溯遍历i的起始值,以防止收割结果时出现重复的组合
records这个数组的大小如果达到k,说明找到了一个子集大小为k的组合,收割结果并结束当前递归
递归回来记得要进行回溯操作,撤销本次处理的结果
回溯法的搜索过程就是一个树型结构的遍历过程,for循环用来横向遍历,递归的过程是纵向遍历

class Solution {
List<List<Integer>> result = new ArrayList<>();
List<Integer> records = new ArrayList<>();
public List<List<Integer>> combine(int n, int k) {
backTracking(n, k, 1);
return result;
}
public void backTracking(int n, int k, int start){
if(records.size() == k){
result.add(new ArrayList<>(records));
return;
}
for(int i = start; i <= n; i++){
records.add(i);
backTracking(n, k, i + 1);
records.removeLast();
}
}
}
加入剪枝操作,优化遍历过程

class Solution {
List<List<Integer>> result = new ArrayList<>();
List<Integer> records = new ArrayList<>();
public List<List<Integer>> combine(int n, int k) {
backTracking(n, k, 1);
return result;
}
public void backTracking(int n, int k, int start){
if(records.size() == k){
result.add(new ArrayList<>(records));
return;
}
for(int i = start; i <= n - (k - records.size()) + 1; i++){
records.add(i);
backTracking(n, k, i + 1);
records.removeLast();
}
}
}
LeetCode216 组合总和Ⅱ
题目链接:https://leetcode.cn/problems/combination-sum-iii/description/
文章讲解:https://programmercarl.com/0216.组合总和III.html
视频讲解:https://www.bilibili.com/video/BV1wg411873x/?vd_source=b989f2b109eb3b17e8178154a7de7a51
本题k相当于树的深度,9(因为整个集合就是9个数)就是树的宽度

class Solution {
List<List<Integer>> result = new ArrayList<>();
List<Integer> records = new ArrayList<>();
int sum = 0;
public List<List<Integer>> combinationSum3(int k, int n) {
backTracking(k, n, 1);
return result;
}
public void backTracking(int k, int n, int start){
if(sum > n){
return;
}
if(sum == n && records.size() == k){
result.add(new ArrayList<>(records));
return;
}
for(int i = start; i <= 9 - (k-records.size()) + 1; i++){
records.add(i);
sum += i;
backTracking(k, n, i+1);
sum -= i;
records.removeLast();
}
}
}
LeetCode17 电话号码的字母组合
题目链接:https://leetcode.cn/problems/letter-combinations-of-a-phone-number/description/
文章讲解:https://programmercarl.com/0017.电话号码的字母组合.html
视频讲解:https://www.bilibili.com/video/BV1yV4y1V7Ug/?vd_source=b989f2b109eb3b17e8178154a7de7a51
数字和字母通过一个String数组进行映射
使用回溯法来解决n个for循环的问题,遍历的深度就是输入digits的长度,而叶子节点就是要收集的结果
此时backTracking这个index是记录遍历第几个数字了,是用来遍历题目中给出的数字字符串digits的,同时index也表示树的深度,不同于之前组合那两题的startIndex
终止条件就是 index == digits.size 时,收割结果并返回
题目所给测试集没有异常数据,但面试时写代码一定要考虑到排除异常数据

class Solution {
String[] letterMap = {" ", " ", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"};
StringBuilder records = new StringBuilder();
List<String> result = new ArrayList<>();
public List<String> letterCombinations(String digits) {
backTracking(digits, 0);
return result;
}
public void backTracking(String digits, int curDigitIndex){
if(curDigitIndex == digits.length()){
result.add(records.toString());
return;
}
int curDigit = digits.charAt(curDigitIndex) - '0';
String letter = letterMap[curDigit];
for(int i = 0; i < letter.length(); i++){
records.append(letter.charAt(i));
backTracking(digits, curDigitIndex+1);
records.deleteCharAt(records.length()-1);
}
}
}

浙公网安备 33010602011771号