【216.组合总和III】中等题
思路:
- 确定终止条件:当路径节点数达到k个时,判断是否要记录该路径,结束递归
- 剪枝:如果到达当前节点的路径之和已经大于n了,就不需要再遍历该节点的子节点了
- 确定单层递归逻辑:遍历所有子节点(处理子节点 -> 递归记录子节点所有可能的结果 -> 回溯恢复现场)
class Solution {
int sum = 0; // 记录路径之和
List<Integer> path = new LinkedList<>(); // 记录路径
List<List<Integer>> res = new ArrayList<>(); // 记录所有和为n的路径
public List<List<Integer>> combinationSum3(int k, int n) {
backtracking(k, n, 1);
return res;
}
public void backtracking(int k, int n, int start){
// 确定终止条件:当路径节点数达到k个时,判断是否要记录该路径,结束递归
if (k == path.size()) {
if (sum == n) res.add(new LinkedList(path));
return;
}
// 剪枝:如果到达当前节点的路径之和已经大于n了,就不需要再遍历该节点的子节点了
if (sum > n) return;
// 确定单层递归逻辑:遍历所有子节点(处理子节点 -> 递归记录子节点所有可能的结果 -> 回溯恢复现场)
for (int i = start; i <= 9; i++){
sum += i;
path.addLast(i);
backtracking(k, n, i + 1);
sum -= i;
path.removeLast();
}
}
}
时间复杂度: O(9^k × k),每个路径k个数,每个数有9种取值可能,即O(9^k),复制O(k)
空间复杂度: O(k)
【17.电话号码的字母组合】中等题
思路:
- 如果输入字符串为null/字符串为长度为0的空字符,直接返回res(此处返回null会报错)
- 建立哈希表(key = 数字,value = 数字在键盘上对应的多个字母字符串)
- 递归 & 回溯,记录所有路径
- 确定终止条件:如果路径长度=输入字符串的长度,记录路径并返回
- 确认单层递归逻辑:获取当前层的所有子节点(kids指第idx个数字在电话按钮上对应的字母字符串),遍历所有子节点,记录子节点的所有路径
- 将当前子节点加入路径
- 记录子节点的所有路径
- 回溯恢复当前节点路径
class Solution {
List<String> res = new ArrayList<>();
StringBuffer path = new StringBuffer();
Map<Character, String> map = new HashMap<>();
public List<String> letterCombinations(String digits) {
// 如果输入字符串为null/字符串为长度为0的空字符,直接返回res(此处返回null会报错)
if (digits == null || digits.length() == 0) return res;
// 建立哈希表(key = 数字,value = 数字在键盘上对应的多个字母字符串)
map.put('2', "abc");
map.put('3', "def");
map.put('4', "ghi");
map.put('5', "jkl");
map.put('6', "mno");
map.put('7', "pqrs");
map.put('8', "tuv");
map.put('9', "wxyz");
// 递归 & 回溯,记录所有路径
backtracking(digits, 0);
return res;
}
public void backtracking(String digits, int idx){
// 确定终止条件:如果路径长度=输入字符串的长度,记录路径并返回
if (path.length() == digits.length()){
res.add(path.toString());
return;
}
// 确认单层递归逻辑:遍历所有子节点,记录子节点的所有路径
String kids = map.get(digits.charAt(idx)); // 获取当前层的所有子节点(kids指第idx个数字在电话按钮上对应的字母字符串)
for (int i = 0; i < kids.length(); i++){
path.append(kids.charAt(i)); // 将当前子节点加入路径
backtracking(digits, idx + 1); // 记录子节点的所有路径
path.deleteCharAt(path.length() - 1); // 回溯恢复当前节点路径
}
}
}
时间复杂度: O(3^N * 4^M),其中 N 是输入字符串中对应数字为 3 和 4 的个数
空间复杂度: O(3^N * 4^M),递归栈占的空间取决于递归的深度O(N+M),结果集的空间取决于最终的组合数量 O(3^N * 4^M),O(3^N * 4^M) > O(N+M)