关于我:
睡觉待开机:个人主页
PDF版免费提供:倘若有需要,想拿我写的博客进行学习和交流,可以私信我将免费提供PDF版。
留下你的建议:倘若你发现本文中的内容和配图有任何错误或改进建议,请直接评论或者私信。
倡导提问与交流:关于本文任何不明之处,请及时评论和私信,看到即回复。
参考目录
- 1.前言
- 2.题目介绍
- 3.题解思路
- 4.代码示例
- 5.时间/空间复杂度分析
1.前言
今天来分享一道比较中规中矩的题目题解,即电话号码的组合。这道题思路上来说很简单,但是前提得理解深度优先遍历。
什么是深度优先遍历?
举个例子,二叉树的中序遍历
(当然二叉树的前序、后序遍历也属于深度优先遍历),按照左子树、根、右子树的方式依次遍历整棵树。
2.题目介绍
题目链接:LINK
这道题题意很简单,给到我们一个字符串,然后字符串里有一些数字字符,每个数字字符对应一个特定的字母字符串,挨个取字母字符串元素,取出所有组合即可。
比如,给到我们的数字字符串是:“234”,那我们的遍历图解如下:
3.题解思路
我们的整体思路使用哈希表存储每个字符数字对应的所有可能的字母,并对其进行回溯。
回溯的过程:我们用一个string类型来维护我们每次维护的字符串结果,得到每个string结果之后,将其尾插到返回结果中去。
该字符串初始为空,每次取电话号码中的一位数字,然后根据这个数字获得该数字对应的所有可能的字母,将其中的一个字母插入到我们维护的string中,然后继续处理电话号码的后一位数字,知道处理完电话号码中的所有数字,即得到一个完整的字母排列。然后进行回退操作,遍历其余的字母排列。
4.代码示例
class Solution {
public:
vector<string> letterCombinations(string digits) {
vector<string> combinations;//用来返回最后的组合结果
if(digits.empty())//如果为空,返回个空vector即可
{
return combinations;
}
//下面开始处理一般情况:
//先制作了哈希表
unordered_map<char, string> phoneMap{
{'2', "abc"},
{'3', "def"},
{'4', "ghi"},
{'5', "jkl"},
{'6', "mno"},
{'7', "pqrs"},
{'8', "tuv"},
{'9', "wxyz"}
};
string combination;//用来存储每个组合,即一个字符串
backtrack(combinations, combination, digits, phoneMap, 0);
//返回
return combinations;
}
void backtrack(vector<string>& combinations, string& combination, const string& digits, const unordered_map<char, string>&phoneMap, int index)
{
//当下标取到digit末尾时候,表示完成了一个string制作,要把它加入到combinations中去
if(index == digits.size())
{
combinations.push_back(combination);
}
else//如果不是,那我们先取digits中的数字,再根据数字拿到对应的string,再取string中所需要的那一位
{
char digit = digits.at(index);
const string& letters = phoneMap.at(digit);
for(auto& letter : letters)
{
combination.push_back(letter);
backtrack(combinations, combination, digits, phoneMap, index+1);
combination.pop_back();
}
}
}
};
5.时间/空间复杂度分析
注意:m指的是给定的一串数字中对应3位字母的数字的个数,n指得是一串数字中对应4位字母得数字得个数。
时间复杂度:O(3^m + 4^n)
时间复杂度主要就是取决于数字长度了,假定每个数字都对应3个字母,那么就是数字个数的三次方,但是存在部分数字是对应四个字母的,所以应该是上面所示。
空间复杂度:O(m + n)
空间复杂度主要取决于两部分,一部分是哈希表,另一部分是我们调用得递归函数所对应的空间开销。其中由于哈希表底层实现,哈希表的空间复杂度为O(1),调用的递归函数最大递归层级就是给定的字符串数字的长度次。
EOF