本题的主要思路:映射->递归 ->回溯
说到“所有组合”我们就应该想到“回溯”,回溯的本质就是穷举,也就是可以把我们的所有组合打印出来。
所有的回溯都可以化为一个抽象的树状结构,画图很主要,方便我们理解。
假设我们传入 “2 3” “2”实际上就是“a b c”,"3"实际上就是" d e f"
然后要求我们去列举所有可能,那我们可以先把取a,把a的所有可能列举,再取b,把b的所有可能列举,再取c,把c的所有可能列举:
然后就是我们收获结果的地方了,收获果实的地方在叶子节点。
ok,图画出来就好写了。
映射
题目给我们穿了一个string的变量digits,假设figotis="2 3",要求我们返回" 2 3"映射的字母排列组合的所有可能
这个数的深度我们一般用递归来处理,因为递归是触底才结束。树的宽度就是子子集的宽度,我们通常用for循环来处理:
开始写代码: 我们可以通过二维数组映射,写一个数组:
vector<string> board = {"", "", "abc", "def", "ghi","jkl","mno","pqrs","tuv","wxyz"};
比如我们想访问 digits的“2” 那我们就board[index][i], index为2,i为0 1 2时可遍历 " a b c"
然后我们来写递归:
递归
void backstracking(int index,string digits)//digits=" 2 3" index为下标,用来访问是"2" 还是"3"
{
}
先写回溯的结束条件,上文说过收获结果的地方在叶子节点,我们可以用一个容器来存放单个叶子节点:
string s
但是有多个叶子节点,所以还需要把所有的s放到一起
result.push_back(s);
我们把叶子节点遍历完就结束。
所以我们可以这样写回溯结束条件:
if(index == digits.size()) return result;
递归代码实现: digits=“ 2 3” 前面说过我们的映射是通过下标来映射,所以我们需要把“2 3”变为数组 2,数字3,这样就可以通过下标来访问了。
int num = digits[index] - '0'; //表示按到了键盘上的第几个键
然后我们先对2 进行递归,首先需要遍历一下abc,把abc分别取出来,也就是刚开始我们说的第二步:
for(int i=0;i<board[nums].size();i++
{
s.push_back(board[num)[i]);
}
然后我们要接着往下递归,再往下递归就要从"d e f"的位置开始递归
我们注意到“ d e f”是“3”里面的,所以我们要访问"3":
backtracking(daigits,index+1)
回溯
此时s里面就有了“ a d”,我们访问到了底部,然后就是回溯的过程。
回溯的过程就是先把"d"弹出去,然后再递归获取“e”,然后再把“e”弹出去,再返回,再递归获取“f”。
code
class Solution {
public:
string s;
vector<string> board = {"", "", "abc", "def", "ghi","jkl","mno","pqrs","tuv","wxyz"};
vector<string> result;
void dfs(int index, string digits){
if(index == digits.size()){
result.push_back(s);
return;
}
int num = digits[index] - '0'; //表示按到了键盘上的第几个键
for(int i = 0; i < board[num].size(); i ++){
s.push_back(board[num][i]);
dfs(index + 1, digits); //递归下一层
s.pop_back(); //回溯
}
}
vector<string> letterCombinations(string digits) {//digits是传入的字符串数字,比如“23”
if(digits.size() == 0) return {};//这一步很重要:当`digits`为空字符串时,`index`会等于`digits.size()`,然后进入`if`条件,把空字符串`s`添加到`result`中,这并不是我们想要的。
dfs(0, digits);
return result;
}
};
第一次调用 dfs(0, "23"),栈内元素为 ["", "23"]
第二次调用 dfs(1, "3"),栈内元素为 ["a", "3"]
第三次调用 dfs(2, ""),栈内元素为 ["ad", ""]
第四次调用 dfs(2, ""),栈内元素为 ["ae", ""]
第五次调用 dfs(2, ""),栈内元素为 ["af", ""]
第六次调用 dfs(1, "3"),栈内元素为 ["b", "3"]
第七次调用 dfs(2, ""),栈内元素为 ["bd", ""]
第八次调用 dfs(2, ""),栈内元素为 ["be", ""]
第九次调用 dfs(2, ""),栈内元素为 ["bf", ""]
第十次调用 dfs(1, "3"),栈内元素为 ["c", "3"]
第十一次调用 dfs(2, ""),栈内元素为 ["cd", ""]
第十二次调用 dfs(2, ""),栈内元素为 ["ce", ""]
第十三次调用 dfs(2, ""),栈内元素为 ["cf", ""]