leetcode 17. 电话号码的字母组合----回溯算法
Posted 大忽悠爱忽悠
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了leetcode 17. 电话号码的字母组合----回溯算法相关的知识,希望对你有一定的参考价值。
电话号码的字母组合题解集合
引言
如果对回溯算法不了解的,建议先看这篇文章
小白易懂的回溯算法!!!
回溯算法
将问题转化为对一颗多叉树的遍历过程,可以大大简化思维和实现难度
由上图可得:
- 递归结束条件: 输入的数字个数与当前已经找到的字母个数一致,说明找到了一个可行方案,然后将可行方案保存到ret数组中
- 递归返回值:void
- 本级递归做什么:遍历当前数字对应剩余的字母,看能否找到其余解
代码:
class Solution {
unordered_map<char, string> map;//保存每个数字映射的字母
vector<string> ret;//保存所有结果组合
public:
vector<string> letterCombinations(string digits)
{
if (digits.empty()) return ret;
//保存每个数字映射的字母
map['2'] = "abc";
map['3'] = "def";
map['4'] = "ghi";
map['5'] = "jkl";
map['6'] = "mno";
map['7'] = "pqrs";
map['8'] = "tuv";
map['9'] = "wxyz";
//组合需要的字母个数
int num = digits.size();
string cur;
dfs(digits, cur,num,0);
return ret;
}
//cur将找到的字母先存放在里面,等到字母个数等于需要的个数时,再压入结果数组
//num: 组合需要的字母个数
//n:当前用到了第一个数字
void dfs(string digits,string cur,int num,int n)
{
if (cur.size() == num)//找到了一个可行解
{
ret.push_back(cur);
return;
}
//遍历当前数字剩余的字母
for (int i = 0; i < map[digits[n]].size(); i++)//注意这里每一层,都是从第一个字母开始进行遍历
{
//把当前数字对应的第index个字母放入cur数组中
cur.push_back(map[digits[n]][i]);
//遍历剩余字母
dfs(digits, cur,num, n + 1);
//回溯
cur.pop_back();
}
}
};
BFS—队列求解
其实上面的DFS的思路就是先选取第一个数字对应的第一个字母,然后去下一层与第二个数字的三个字母分别进行组合,组合完后,再取第一个数字对应的第二个字母,同样去下一层与第二个数字的三个字母进行组合,接着是第一个数字对应的第三个字母…
那么这里同样可以利用BFS的方法实现上述思路,看图:
我们可以利用队列的先进先出特点,再配合循环完成题目要求。
我们先将2对应的字符"a",“b”,“c"依次放入队列中
之后再从队列中拿出第一个元素"a”,跟3对应的字符"d",“e”,“f"挨个拼接
于是队列就变成了下面这个样子:
按照同样的方式,再将"b"从队列中拿出,再跟3对应的字符"d”,“e”,"f"挨个拼接,队列又变成下面这个样子:
注意这里BFS的思路:
新一层在上一层的末尾添加字符得到;
新一层得到了以后,上一层就不用了;
最开始的时候,是一个空字符串。
代码;
class Solution {
unordered_map<char, string> store;
vector<string> ret;//保存所有结果组合
public:
vector<string> letterCombinations(string digits)
{
if (digits.empty()) return ret;
//储存字典
store = unordered_map<char, string>{
{'2', "abc"}, {'3', "def"}, {'4', "ghi"}, {'5', "jkl"}, {'6', "mno"}, {'7', "pqrs"}, {'8', "tuv"}, {'9', "wxyz"} };
//组合需要的字母个数
int num = digits.size();
string cur;
queue<string> q;
q.push("");
for (auto cur : digits)//cur表示遍历的当前层
{
string curStr = store[cur];//获取当前数字对应的字符串---即需要进行遍历的字母
int size = q.size();//获取当前队列的长度
//将当前层元素出队
for (int i = 0; i < size; i++)
{
string tempStr = q.front();
q.pop();
for (auto tempChar : curStr)//将下一层元素前面加上当前要出队元素后,入队
{
q.push(tempStr + tempChar);
}
}
}
while (!q.empty())
{
string tempStr = q.front(); q.pop();
ret.push_back(tempStr);
}
return ret;
}
};
总结
本题主要还是想要大家理解回溯算法的思想,而BFS只是作为一个扩展。
下面我来总结一下回溯算法的基本模板:
确定结束回溯过程的 Base case
遍历所有的选择
对选择进行决策(做选择--->递归---->撤销选择)
伪代码:
void dfs(路径,选择列表,结果集)
{
if(满足结束条件)
{
结果集.add(路径);
return;
}
for(选择:选择列表)
{
做选择;
dfs(路径,选择列表,结果集);
撤销选择;
}
}
以上是关于leetcode 17. 电话号码的字母组合----回溯算法的主要内容,如果未能解决你的问题,请参考以下文章