216.组合总和III
相对于77. 组合 (opens new window),无非就是多了一个限制,本题是要找到和为n的k个数的组合,而整个集合已经是固定的了[1,...,9]。
已选元素总和如果已经大于n(图中数值为4)了,那么往后遍历就没有意义了,直接剪掉。
for循环的范围也可以剪枝,i <= 9 - (k - path.size()) + 1就可以了。
当前递归中,组合中目前已经有path.size()个元素,题目要求有k个,
还需要/还缺:k-path.size()个元素
i控制的是取每个组合的每个集合里的起始位置
i至多只能到9-(k-path.size()),才能满足后面的元素,足够填补上空缺的元素
9-(k-path.size())+1:下标补齐
class Solution {
List<List<Integer>> result = new ArrayList<>();// 存放结果集
List<Integer> path = new ArrayList<>();// 符合条件的结果
public List<List<Integer>> combinationSum3(int k, int n) {
trackbacking(k, n, 1, 0);
return result;
}
// targetSum:目标和,也就是题目中的n。
// k:题目中要求k个数的集合。
// sum:已经收集的元素的总和,也就是path里元素的总和。
// startIndex:下一层for循环搜索的起始位置。
public void trackbacking(int k, int n, int startIndex, int sum){
if(sum > n) return; // 剪枝操作,已选元素总和如果已经大于n了,那么往后遍历就没有意义了,直接剪掉
if(path.size() == k){
if(sum == n) result.add(new ArrayList<>(path));
return;// 如果path.size() == k 但sum != targetSum 直接返回
}
for(int i = startIndex; i <= 9 - (k - path.size()) + 1; i++){//for循环的范围也可以剪枝
sum += i;
path.add(i);
trackbacking(k, n, i + 1, sum);// 注意i+1调整startIndex
sum -= i;// 回溯
path.remove(Integer.valueOf(i));// 回溯
}
}
}
17.电话号码的字母组合
本题大家刚开始做会有点难度,先自己思考20min,没思路就直接看题解。
题目链接/文章讲解:代码随想录
本题是两个集合里的元素做组合,就不需要startIndex来帮忙控制,集合里我们之前遍历过哪些元素。
index是记录遍历第几个数字了,就是用来遍历digits的(题目中给出数字字符串),同时index也表示树的深度。
叶子节点就是要收集的结果集。
那么终止条件就是如果index 等于 输入的数字个数(digits.size)了(本来index就是用来遍历digits的)。然后收集结果,结束本层递归。
class Solution {
//设置全局列表存储最后的结果
List<String> result = new ArrayList<>();
//每次迭代获取一个字符串,所以会设计大量的字符串拼接,所以这里选择更为高效的 StringBuild
StringBuilder path = new StringBuilder();
//初始对应所有的数字,为了直接对应2-9,新增了两个无效的字符串""
String[] letterMap = {
"", // 0
"", // 1
"abc", // 2
"def", // 3
"ghi", // 4
"jkl", // 5
"mno", // 6
"pqrs", // 7
"tuv", // 8
"wxyz", // 9
};
public List<String> letterCombinations(String digits) {
if(digits == null || digits.length() == 0) return result;
//迭代处理
trackingback(digits, 0);
return result;
}
//比如digits如果为"23",num 为0,则str表示2对应的 abc
public void trackingback(String digits, int index){
//遍历全部一次记录一次得到的字符串
if(digits.length() == index){
result.add(path.toString());
return;
}
//str 表示当前num对应的字符串
int digit = digits.charAt(index) - '0';// 将index指向的数字转为int
String letter = letterMap[digit];// 取数字对应的字符集
for(int i = 0; i < letter.length(); i++){
path.append(letter.charAt(i));// 处理
trackingback(digits, index + 1);// 递归,注意index+1,一下层要处理下一个数字了
path.delete(path.length() - 1, path.length());// 回溯,剔除末尾的继续尝试
}
}
}