文章目录
day25学习内容
day25主要内容
- 组合总和
- 电话号码的字母组合
声明
本文思路和文字,引用自《代码随想录》
一、组合总和
1.1、代码-无剪枝
class Solution {
private List<List<Integer>> result = new ArrayList();
List<Integer> path = new ArrayList();
public List<List<Integer>> combinationSum3(int k, int n) {
backtracking(k, n, 1, 0);
return result;
}
private void backtracking(int k, int n, int startIndex, int sum) {
if (sum > n) {
return;
}
//和正好等于n,并且选取的元素等于k
if (path.size() == k && n == sum) {
result.add(new ArrayList(path));
return;
}
for (int i = startIndex; i <= 9; i++) {
//单节点操作
path.add(i);
sum += i;
backtracking(k, n, i + 1, sum);
//回溯
sum -= i;
path.removeLast();
}
}
}
1.1.1、为什么是i <= 9而不是i<=n
看题目。很显然是小于9而不是小于n
1.2、代码-剪枝优化
class Solution {
private List<List<Integer>> result = new ArrayList();
List<Integer> path = new ArrayList();
public List<List<Integer>> combinationSum3(int k, int n) {
backtracking(k, n, 1, 0);
return result;
}
private void backtracking(int k, int n, int startIndex, int sum) {
if (sum > n) {
return;
}
//和正好等于n,并且选取的元素等于k
if (path.size() == k && n == sum) {
result.add(new ArrayList(path));
return;
}
for (int i = startIndex; i <= 9 - (k - path.size()) + 1; i++) {
//单节点操作
path.add(i);
sum += i;
backtracking(k, n, i + 1, sum);
//回溯
sum -= i;
path.removeLast();
}
}
}
1.2.1、为什么是i <= 9 - (k - path.size()) + 1;而不是i <= n - (k - path.size()) + 1;
- 首先根据题目要求,取数范围必须要1-9范围内。
公式咋推导出来的
?- 去看一下【代码随想录刷题day24|回溯理论基础&组合问题】,可以得到n-i+1>=k-path.size()
- 所以推导出i <= 9 - (k - path.size()) + 1(基础的数组,-i要取反而已。。)
二、电话号码的字母组合
2.1、思路
- 数字和字母如何映射??
- 可以用一个map映射
写不出来,抄的题解
2.2、正确写法1,官方题解
class Solution {
public List<String> letterCombinations(String digits) {
List<String> result = new ArrayList();
if (digits.length() == 0) {
return result;
}
Map<Character, String> phoneMap = new HashMap<Character, String>() {
{
put('2', "abc");
put('3', "def");
put('4', "ghi");
put('5', "jkl");
put('6', "mno");
put('7', "pqrs");
put('8', "tuv");
put('9', "wxyz");
}
};
backTracking(result, phoneMap, digits, 0, new StringBuffer());
return result;
}
private void backTracking(List<String> result, Map<Character, String> phoneMap, String digits, int index,
StringBuffer sb) {
if (index == digits.length()) {
result.add(sb.toString());
} else {
char digit = digits.charAt(index);
String s = phoneMap.get(digit);
int count = s.length();
for (int i = 0; i < count; i++) {
sb.append(s.charAt(i));
backTracking(result, phoneMap, digits, index + 1, sb);
sb.deleteCharAt(index);
}
}
}
}
2.2.1、分析上述代码
假设输入的数字字符串为 "23"
,逐步解析如何得到所有的字母组合。
电话按键映射
- ‘2’ -> “abc”
- ‘3’ -> “def”
步骤分析
-
初始化:
index
初始化为 0,表示我们将从数字字符串的第一个数字开始处理。digits
是"23"
。result
是我们要填充的字母组合列表。phoneMap
包含数字到字母的映射。
-
对第一个数字’2’进行处理:
index
现在是 0,所以当前处理的数字是digits.charAt(index)
-> ‘2’。- 根据
phoneMap
,‘2’ 对应的字母是 “abc”。 - 我们将遍历这三个字母(‘a’, ‘b’, ‘c’)。
-
对每个字母进行递归:
- 首先处理字母 ‘a’:
- 将 ‘a’ 加入到
StringBuffer sb
中。 - 递归调用
backTracking
,此时index = 1
,表示将处理下一个数字’3’。
- 将 ‘a’ 加入到
- 当处理数字’3’:
- ‘3’ 对应的字母是 “def”。
- 我们将遍历这三个字母(‘d’, ‘e’, ‘f’),对于每个字母:
- 将字母加入到
sb
中(现在sb
中已有 ‘a’)。 - 因为
index
加 1 后等于digits
长度,我们将sb
中的字符串(如 “ad”)添加到结果列表result
中。 - 然后,我们回溯,从
sb
中移除最后一个字符,尝试下一个字母。
- 将字母加入到
- 首先处理字母 ‘a’:
结果生成流程
- 对于’2’中的’a’,然后是’3’中的’d’,得到"ad"。
- 回溯到’3’,尝试’e’,得到"ae"。
- 回溯到’3’,尝试’f’,得到"af"。
- 回溯到’2’,尝试’b’,然后对’3’的每个字符重复上述过程,得到"bd", “be”, “bf”。
- 回溯到’2’,尝试’c’,然后对’3’的每个字符重复上述过程,得到"cd", “ce”, “cf”。
结果
: ["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"]
总结
1.感想
- 电话号码的字母组合,写不出来,抄题解。。
2.思维导图
本文思路引用自代码随想录,感谢代码随想录作者。