题目:给定一个仅包含数字 2-9
的字符串,返回所有它能表示的字母组合。
给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。
示例:
输入:"23" 输出:["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"].
解法一:
对于输入"234", 我们可以先固定第一个数字, 先求得输入"34"的情况,然后在把2对应的每一个字符分别跟每一个结果组合, 这样就变成了讨论输入"34"的情形了, 以此类推, 可以用递归来做
1 class Solution { 2 public: 3 Solution() 4 { 5 dicts = { 6 {}, {}, 7 {"a", "b", "c"}, 8 {"d", "e", "f"}, 9 {"g", "h", "i"}, 10 {"j", "k", "l"}, 11 {"m", "n", "o"}, 12 {"p", "q", "r", "s"}, 13 {"t", "u", "v"}, 14 {"w", "x", "y", "z"} 15 }; 16 } 17 vector<string> letterCombinations(string digits) { 18 if(digits.size() == 0) 19 return {}; 20 if(digits.size() == 1) 21 return dicts[digits[0]-'0']; 22 vector<string> res; 23 vector<string> sr = letterCombinations(digits.substr(1, digits.size()-1)); 24 for(auto c : dicts[digits[0] - '0']) 25 { 26 for(auto s : sr) 27 { 28 res.push_back(c+s); 29 } 30 } 31 return res; 32 } 33 private: 34 vector<vector<string>> dicts; 35 };
这种方法无论空间还是时间复杂度都比较高
解法二:
1 class Solution { 2 public: 3 Solution() 4 { 5 dicts = { 6 {}, {}, 7 {"a", "b", "c"}, 8 {"d", "e", "f"}, 9 {"g", "h", "i"}, 10 {"j", "k", "l"}, 11 {"m", "n", "o"}, 12 {"p", "q", "r", "s"}, 13 {"t", "u", "v"}, 14 {"w", "x", "y", "z"} 15 }; 16 } 17 vector<string> letterCombinations(string digits) { 18 if(digits.size() == 0) 19 return {}; 20 if(digits.size() == 1) 21 return dicts[digits[0]-'0']; 22 int rsize = 1; 23 for(auto c : digits) 24 { 25 rsize *= dicts[c-'0'].size(); 26 } 27 vector<string> res(rsize, ""); 28 for(int i =0;i < digits.size();++i) 29 { 30 char c = digits[i]; 31 int p = 0; 32 int ds = dicts[c-'0'].size(); 33 rsize /= ds; 34 while(p < res.size()) 35 { 36 res[p] += dicts[c-'0'][(p/rsize)%ds]; 37 p++; 38 } 39 } 40 41 return res; 42 } 43 private: 44 vector<vector<string>> dicts; 45 };
这里说明一下36行, 首先经过33行的计算, rsize表示每一个字符在当前区段应当出现的次数, 来看输入“23”, 它的结果按如下方式排列的话会比较容易理解
ad ae af bd be bf cd ce cf
可以看到, 对于2的可能字符,它在大的区段0~9中, 每一个都连续出现了9/3=3次, 而对于3可能的字符, 分别在2的每种情况下的小区段0~3中连续出现了3/3=1次
这样就可以理解36行中的(p/rsize)%ds的作用了, 首先p/rsize 可以保证连续的rsize都是同一字符, 其次%ds用来确定应该是第几个字符