Skip to content

Commit b4fefff

Browse files
Update
1 parent 0d30cba commit b4fefff

9 files changed

+1381
-12
lines changed

README.md

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,10 @@
1717
</a>
1818

1919
<p align="center">
20-
<a href="https://github.com/youngyangyang04/leetcode-master"><img src="https://img.shields.io/badge/Github-leetcode--master-lightgrey" alt=""></a>
21-
<a href="https://img-blog.csdnimg.cn/20201115103410182.png"><img src="https://img.shields.io/badge/刷题-微信群-green" alt=""></a>
20+
<a href="https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ"><img src="https://img.shields.io/badge/知识星球-代码随想录-blue" alt=""></a>
21+
<a href="https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw"><img src="https://img.shields.io/badge/刷题-微信群-green" alt=""></a>
2222
<a href="https://img-blog.csdnimg.cn/20201210231711160.png"><img src="https://img.shields.io/badge/公众号-代码随想录-brightgreen" alt=""></a>
2323
<a href="https://space.bilibili.com/525438321"><img src="https://img.shields.io/badge/B站-代码随想录-orange" alt=""></a>
24-
<a href="https://www.zhihu.com/people/sun-xiu-yang-64"><img src="https://img.shields.io/badge/知乎-代码随想录-blue" alt=""></a>
25-
<a href="https://www.toutiao.com/c/user/60356270818/#mid=1633692776932365"><img src="https://img.shields.io/badge/头条-代码随想录-red" alt=""></a>
2624
</p>
2725

2826
<p align="center">
@@ -130,8 +128,8 @@
130128
## 数组
131129

132130
1. [数组过于简单,但你该了解这些!](./problems/数组理论基础.md)
133-
2. [数组:每次遇到二分法,都是一看就会,一写就废](https://mp.weixin.qq.com/s/fCf5QbPDtE6SSlZ1yh_q8Q)
134-
3. [数组:就移除个元素很难么?](https://mp.weixin.qq.com/s/wj0T-Xs88_FHJFwayElQlA)
131+
2. [数组:每次遇到二分法,都是一看就会,一写就废](./problems/0704.二分查找.md)
132+
3. [数组:就移除个元素很难么?](./problems/0027.移除元素.md)
135133
4. [数组:滑动窗口拯救了你](https://mp.weixin.qq.com/s/UrZynlqi4QpyLlLhBPglyg)
136134
5. [数组:这个循环可以转懵很多人!](https://mp.weixin.qq.com/s/KTPhaeqxbMK9CxHUUgFDmg)
137135
6. [数组:总结篇](https://mp.weixin.qq.com/s/LIfQFRJBH5ENTZpvixHEmg)
@@ -248,11 +246,11 @@
248246
<img src='https://img-blog.csdnimg.cn/20210219192050666.png' width=600 alt='回溯算法大纲'> </img></div>
249247

250248
1. [关于回溯算法,你该了解这些!](./problems/回溯算法理论基础.md)
251-
2. [回溯算法:求组合问题!](https://mp.weixin.qq.com/s/OnBjbLzuipWz_u4QfmgcqQ)
252-
3. [回溯算法:组合问题再剪剪枝](https://mp.weixin.qq.com/s/Ri7spcJMUmph4c6XjPWXQA)
253-
4. [回溯算法:求组合总和!](https://mp.weixin.qq.com/s/HX7WW6ixbFZJASkRnCTC3w)
254-
5. [回溯算法:电话号码的字母组合](https://mp.weixin.qq.com/s/e2ua2cmkE_vpYjM3j6HY0A)
255-
6. [本周小结!(回溯算法系列一)](https://mp.weixin.qq.com/s/m2GnTJdkYhAamustbb6lmw)
249+
2. [回溯算法:组合问题](./problems/0077.组合.md)
250+
3. [回溯算法:组合问题再剪剪枝](./problems/0077.组合优化.md)
251+
4. [回溯算法:求组合总和!](./problems/0216.组合总和III.md)
252+
5. [回溯算法:电话号码的字母组合](./problems/0017.电话号码的字母组合.md)
253+
6. [本周小结!(回溯算法系列一)](./problems/周总结/20201030回溯周末总结.md)
256254
7. [回溯算法:求组合总和(二)](https://mp.weixin.qq.com/s/FLg8G6EjVcxBjwCbzpACPw)
257255
8. [回溯算法:求组合总和(三)](https://mp.weixin.qq.com/s/_1zPYk70NvHsdY8UWVGXmQ)
258256
9. [回溯算法:分割回文串](https://mp.weixin.qq.com/s/Pb1epUTbU8fHIht-g_MS5Q)
Lines changed: 243 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,243 @@
1+
2+
<p align="center">
3+
<a href="https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ"><img src="https://img.shields.io/badge/知识星球-代码随想录-blue" alt=""></a>
4+
<a href="https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw"><img src="https://img.shields.io/badge/刷题-微信群-green" alt=""></a>
5+
<a href="https://img-blog.csdnimg.cn/20201210231711160.png"><img src="https://img.shields.io/badge/公众号-代码随想录-brightgreen" alt=""></a>
6+
<a href="https://space.bilibili.com/525438321"><img src="https://img.shields.io/badge/B站-代码随想录-orange" alt=""></a>
7+
</p>
8+
9+
# 17.电话号码的字母组合
10+
11+
题目链接:https://leetcode-cn.com/problems/letter-combinations-of-a-phone-number/
12+
13+
给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。
14+
15+
给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。
16+
17+
![17.电话号码的字母组合](https://img-blog.csdnimg.cn/2020102916424043.png)
18+
19+
示例:
20+
输入:"23"
21+
输出:["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"].
22+
23+
说明:尽管上面的答案是按字典序排列的,但是你可以任意选择答案输出的顺序。
24+
25+
# 思路
26+
27+
从示例上来说,输入"23",最直接的想法就是两层for循环遍历了吧,正好把组合的情况都输出了。
28+
29+
如果输入"233"呢,那么就三层for循环,如果"2333"呢,就四层for循环.......
30+
31+
大家应该感觉出和[回溯算法:求组合问题!](https://mp.weixin.qq.com/s/OnBjbLzuipWz_u4QfmgcqQ)遇到的一样的问题,就是这for循环的层数如何写出来,此时又是回溯法登场的时候了。
32+
33+
理解本题后,要解决如下三个问题:
34+
35+
1. 数字和字母如何映射
36+
2. 两个字母就两个for循环,三个字符我就三个for循环,以此类推,然后发现代码根本写不出来
37+
3. 输入1 * #按键等等异常情况
38+
39+
## 数字和字母如何映射
40+
41+
可以使用map或者定义一个二位数组,例如:string letterMap[10],来做映射,我这里定义一个二维数组,代码如下:
42+
43+
```
44+
const string letterMap[10] = {
45+
"", // 0
46+
"", // 1
47+
"abc", // 2
48+
"def", // 3
49+
"ghi", // 4
50+
"jkl", // 5
51+
"mno", // 6
52+
"pqrs", // 7
53+
"tuv", // 8
54+
"wxyz", // 9
55+
};
56+
```
57+
58+
## 回溯法来解决n个for循环的问题
59+
60+
对于回溯法还不了解的同学看这篇:[关于回溯算法,你该了解这些!](https://mp.weixin.qq.com/s/gjSgJbNbd1eAA5WkA-HeWw)
61+
62+
63+
例如:输入:"23",抽象为树形结构,如图所示:
64+
65+
![17. 电话号码的字母组合](https://img-blog.csdnimg.cn/20201123200304469.png)
66+
67+
图中可以看出遍历的深度,就是输入"23"的长度,而叶子节点就是我们要收集的结果,输出["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"]
68+
69+
回溯三部曲:
70+
71+
* 确定回溯函数参数
72+
73+
首先需要一个字符串s来收集叶子节点的结果,然后用一个字符串数组result保存起来,这两个变量我依然定义为全局。
74+
75+
再来看参数,参数指定是有题目中给的string digits,然后还要有一个参数就是int型的index。
76+
77+
注意这个index可不是 [回溯算法:求组合问题!](https://mp.weixin.qq.com/s/OnBjbLzuipWz_u4QfmgcqQ)[回溯算法:求组合总和!](https://mp.weixin.qq.com/s/HX7WW6ixbFZJASkRnCTC3w)中的startIndex了。
78+
79+
这个index是记录遍历第几个数字了,就是用来遍历digits的(题目中给出数字字符串),同时index也表示树的深度。
80+
81+
代码如下:
82+
83+
```
84+
vector<string> result;
85+
string s;
86+
void backtracking(const string& digits, int index)
87+
```
88+
89+
* 确定终止条件
90+
91+
例如输入用例"23",两个数字,那么根节点往下递归两层就可以了,叶子节点就是要收集的结果集。
92+
93+
那么终止条件就是如果index 等于 输入的数字个数(digits.size)了(本来index就是用来遍历digits的)。
94+
95+
然后收集结果,结束本层递归。
96+
97+
代码如下:
98+
99+
```
100+
if (index == digits.size()) {
101+
result.push_back(s);
102+
return;
103+
}
104+
```
105+
106+
* 确定单层遍历逻辑
107+
108+
首先要取index指向的数字,并找到对应的字符集(手机键盘的字符集)。
109+
110+
然后for循环来处理这个字符集,代码如下:
111+
112+
```
113+
int digit = digits[index] - '0'; // 将index指向的数字转为int
114+
string letters = letterMap[digit]; // 取数字对应的字符集
115+
for (int i = 0; i < letters.size(); i++) {
116+
s.push_back(letters[i]); // 处理
117+
backtracking(digits, index + 1); // 递归,注意index+1,一下层要处理下一个数字了
118+
s.pop_back(); // 回溯
119+
}
120+
```
121+
122+
**注意这里for循环,可不像是在[回溯算法:求组合问题!](https://mp.weixin.qq.com/s/OnBjbLzuipWz_u4QfmgcqQ)[回溯算法:求组合总和!](https://mp.weixin.qq.com/s/HX7WW6ixbFZJASkRnCTC3w)中从startIndex开始遍历的**
123+
124+
**因为本题每一个数字代表的是不同集合,也就是求不同集合之间的组合,而[77. 组合](https://mp.weixin.qq.com/s/OnBjbLzuipWz_u4QfmgcqQ)[216.组合总和III](https://mp.weixin.qq.com/s/HX7WW6ixbFZJASkRnCTC3w)都是是求同一个集合中的组合!**
125+
126+
127+
注意:输入1 * #按键等等异常情况
128+
129+
代码中最好考虑这些异常情况,但题目的测试数据中应该没有异常情况的数据,所以我就没有加了。
130+
131+
**但是要知道会有这些异常,如果是现场面试中,一定要考虑到!**
132+
133+
134+
## C++代码
135+
136+
关键地方都讲完了,按照[关于回溯算法,你该了解这些!](https://mp.weixin.qq.com/s/gjSgJbNbd1eAA5WkA-HeWw)中的回溯法模板,不难写出如下C++代码:
137+
138+
139+
```
140+
// 版本一
141+
class Solution {
142+
private:
143+
const string letterMap[10] = {
144+
"", // 0
145+
"", // 1
146+
"abc", // 2
147+
"def", // 3
148+
"ghi", // 4
149+
"jkl", // 5
150+
"mno", // 6
151+
"pqrs", // 7
152+
"tuv", // 8
153+
"wxyz", // 9
154+
};
155+
public:
156+
vector<string> result;
157+
string s;
158+
void backtracking(const string& digits, int index) {
159+
if (index == digits.size()) {
160+
result.push_back(s);
161+
return;
162+
}
163+
int digit = digits[index] - '0'; // 将index指向的数字转为int
164+
string letters = letterMap[digit]; // 取数字对应的字符集
165+
for (int i = 0; i < letters.size(); i++) {
166+
s.push_back(letters[i]); // 处理
167+
backtracking(digits, index + 1); // 递归,注意index+1,一下层要处理下一个数字了
168+
s.pop_back(); // 回溯
169+
}
170+
}
171+
vector<string> letterCombinations(string digits) {
172+
s.clear();
173+
result.clear();
174+
if (digits.size() == 0) {
175+
return result;
176+
}
177+
backtracking(digits, 0);
178+
return result;
179+
}
180+
};
181+
```
182+
183+
一些写法,是把回溯的过程放在递归函数里了,例如如下代码,我可以写成这样:(注意注释中不一样的地方)
184+
185+
```
186+
// 版本二
187+
class Solution {
188+
private:
189+
const string letterMap[10] = {
190+
"", // 0
191+
"", // 1
192+
"abc", // 2
193+
"def", // 3
194+
"ghi", // 4
195+
"jkl", // 5
196+
"mno", // 6
197+
"pqrs", // 7
198+
"tuv", // 8
199+
"wxyz", // 9
200+
};
201+
public:
202+
vector<string> result;
203+
void getCombinations(const string& digits, int index, const string& s) { // 注意参数的不同
204+
if (index == digits.size()) {
205+
result.push_back(s);
206+
return;
207+
}
208+
int digit = digits[index] - '0';
209+
string letters = letterMap[digit];
210+
for (int i = 0; i < letters.size(); i++) {
211+
getCombinations(digits, index + 1, s + letters[i]); // 注意这里的不同
212+
}
213+
}
214+
vector<string> letterCombinations(string digits) {
215+
result.clear();
216+
if (digits.size() == 0) {
217+
return result;
218+
}
219+
getCombinations(digits, 0, "");
220+
return result;
221+
222+
}
223+
};
224+
```
225+
226+
我不建议把回溯藏在递归的参数里这种写法,很不直观,我在[二叉树:以为使用了递归,其实还隐藏着回溯](https://mp.weixin.qq.com/s/ivLkHzWdhjQQD1rQWe6zWA)这篇文章中也深度分析了,回溯隐藏在了哪里。
227+
228+
所以大家可以按照版本一来写就可以了。
229+
230+
# 总结
231+
232+
本篇将题目的三个要点一一列出,并重点强调了和前面讲解过的[77. 组合](https://mp.weixin.qq.com/s/OnBjbLzuipWz_u4QfmgcqQ)[216.组合总和III](https://mp.weixin.qq.com/s/HX7WW6ixbFZJASkRnCTC3w)的区别,本题是多个集合求组合,所以在回溯的搜索过程中,都有一些细节需要注意的。
233+
234+
其实本题不算难,但也处处是细节,大家还要自己亲自动手写一写。
235+
236+
------------------------
237+
238+
* 微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
239+
* B站:[代码随想录](https://space.bilibili.com/525438321)
240+
* 知识星球:[代码随想录](https://mp.weixin.qq.com/s/QVF6upVMSbgvZy8lHZS3CQ)
241+
242+
![](https://img-blog.csdnimg.cn/20210416110157800.png)
243+

0 commit comments

Comments
 (0)