题目描述
知识点
回溯
实现
码前思考
- emmm,这难道要用暴力进行求解?感觉无论如何时间复杂度都是 O ( 3 N ∗ 4 ∗ M ) O(3^N*4*M) O(3N∗4∗M),其中 N + M = d i g i t s . s i z e ( ) N+M=digits.size() N+M=digits.size(),不可能再进行优化了。。。
代码实现
//感觉就是非常正常的字符串模拟题吧。。。也许是?
//再加上一点hash的思想
class Solution {
public:
vector<string> letterCombinations(string digits) {
//进行特判
if(digits.size() == 0){
return {};
}
//首先建立字符“2..9”到字母集合的映射
map<char,vector<string> > mp;
//可以像下面这样初始化vector!学到了
mp['2'] = {"a","b","c"};
mp['3'] = {"d","e","f"};
mp['4'] = {"g","h","i"};
mp['5'] = {"j","k","l"};
mp['6'] = {"m","n","o"};
mp['7'] = {"p","q","r","s"};
mp['8'] = {"t","u","v"};
mp['9'] = {"w","x","y","z"};
//定义一个pre,一个after
vector<string> pre;
vector<string> after;
//初始化pre
for(string c : mp[digits[0]]){
pre.push_back(c);
}
int size = digits.size();
for(int i=1;i<size;i++){
char digit = digits[i];
for(string str : pre){
for(string c : mp[digit]){
after.push_back(str+c);
}
}
pre = after;
after.clear();
}
return pre;
}
};
码后反思
- 看见题解里面写用回溯(没有剪枝的回溯),感觉那样才是考点,我上面写的完全就是暴力枚举了,回溯更加专业一些~~代码如下:
//感觉就是非常正常的字符串模拟题吧。。。也许是?
//再加上一点hash的思想
class Solution {
private:
//首先建立字符“2..9”到字母集合的映射
map<char,string> mp;
//结果
vector<string> ans;
//记录匹配情况的字符串
string current;
public:
vector<string> letterCombinations(string digits) {
//进行特判
if(digits.size() == 0){
return {};
}
mp['2'] = "abc";
mp['3'] = "def";
mp['4'] = "ghi";
mp['5'] = "jkl";
mp['6'] = "mno";
mp['7'] = "pqrs";
mp['8'] = "tuv";
mp['9'] = "wxyz";
//从digits的第一位开始进行回溯,也就是对一棵树进行遍历
dfs(0,digits);
return ans;
}
//注意string最好是传地址更快些
void dfs(int index,string& digits){
if(index == digits.size()){
ans.push_back(current);
}
for(char c : mp[digits[index]]){
//压入尾元素
current.push_back(c);
dfs(index+1,digits);
//删除尾元素
current.pop_back();
}
}
};
- 上面的代码更加规范!用到了算法的回溯思想!
- 原来
string
类型也可以push_back()
和pop_back()
,长知识了!
二刷代码
依然只会暴力求解。没有想到回溯的写法。。。
回溯主要在于这个回溯树的理解,如果你在解题的时候,脑子中有了一棵树,那么就可以使用回溯算法!回溯算法的核心就是DFS