leetcode 17. Letter Combinations of a Phone Number
题目
电话号码字母组合
leetcode 17. Letter Combinations of a Phone Number
思路
回溯思想(dfs)
本题中无需剪枝
时间复杂度 O(3n * 4m)
空间复杂度 O(n+m)
运行时间 8 ms
内存消耗 7.9 MB
m 是输入中对应 3个字母的数字个数(包括数字 2、3、4、5、6、8),n是输入中对应 4个字母的数字个数(包括数字 7、9),m+n是输入数字的总个数。
时间复杂度:当输入包含 m个对应 3个字母的数字和 n个对应 4个字母的数字时,不同的字母组合一共有 3n * 4m种,需要遍历每一种字母组合
空间复杂度:主要取决于哈希表以及回溯过程中的递归调用层数,哈希表的大小与输入无关,可以看成常数,递归调用层数最大为 m+n(即输入字符串中数字字符个数)
队列(bfs)
时间复杂度 O(nm(n+m))
空间复杂度 O(n*m)
运行时间 4 ms
内存消耗 6.8 MB
m 是输入中对应 3个字母的数字个数(包括数字 2、3、4、5、6、8),n是输入中对应 4个字母的数字个数(包括数字 7、9),m+n是输入数字的总个数。
时间复杂度:需要n+m轮处理,每轮处理复杂度最大为4nm,总时间复杂度为O(nm(n+m))
空间复杂度:队列长度最大为n*m
代码
回溯思想(dfs)
class Solution {
public:
vector<string> letterCombinations(string digits) {
vector<string> combinations; //所有结果容器
if(digits.empty()){ //易错:如果没有这个判断,输入""错误输出[""],而正确输出是[]
return combinations;
}
unordered_map<char, string> phoneMap { //hash字典表
{'0', ""},
{'1', ""},
{'2', "abc"},
{'3', "def"},
{'4', "ghi"},
{'5', "jkl"},
{'6', "mno"},
{'7', "pqrs"},
{'8', "tuv"},
{'9', "wxyz"}
};
string combination;
backtrack(combinations, phoneMap, digits, 0, combination); //核心方法-回溯
return combinations;
}
void backtrack(vector<string> &combinations, unordered_map<char,string> phoneMap, const string& digits,int index, string combination) {
if(index==digits.length()) { //已经走完一个分支
combinations.push_back(combination);
} else {
char digit = digits[index];
const string & letters=phoneMap[digit];
for(const char & letter: letters) {
combination.push_back(letter);
backtrack(combinations,phoneMap,digits,index+1,combination);
combination.pop_back();
}
}
}
};
易错点
if(digits.empty()){
// 易错:如果没有这个判断,输入""错误输出[""],而正确输出是[]
// 因为bracktrack方法中第一步即使输入为空,也会插入一个空的字符串到结果容器中
return combinations;
}
队列(bfs)
class Solution {
public:
vector<string> letterCombinations(string digits) {
vector<string> combinations;
if(digits.empty()) {
return combinations;
}
queue<string> q;
q.push("");
string phoneMap []= {"","","abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"};
for(int i=0; i<digits.length(); i++) {
string letters = phoneMap[digits[i]-'0'];
q.push("-"); //分隔符
while(!q.empty()) {
string now = q.front();
q.pop();
if(now=="-")break; //遇到分隔符表示本轮处理结束
for(const char & letter: letters) {
string temp = now+letter;
q.push(temp);
}
}
}
while(!q.empty()) {
combinations.push_back(q.front());
q.pop();
}
return combinations;
}
};
易错点
分隔符处理
分割符的处理
每轮开始之前插入,队列处理到分隔符表示本轮处理结束,退出
字符串队列插入空字符串
queue<string> q;
q.push("");
cout<<q.size(); //1
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 为什么说在企业级应用开发中,后端往往是效率杀手?
· 用 C# 插值字符串处理器写一个 sscanf
· Java 中堆内存和栈内存上的数据分布和特点
· 开发中对象命名的一点思考
· .NET Core内存结构体系(Windows环境)底层原理浅谈
· 为什么说在企业级应用开发中,后端往往是效率杀手?
· DeepSeek 解答了困扰我五年的技术问题。时代确实变了!
· 本地部署DeepSeek后,没有好看的交互界面怎么行!
· 趁着过年的时候手搓了一个低代码框架
· 推荐一个DeepSeek 大模型的免费 API 项目!兼容OpenAI接口!