leetcode 17: 电话号码的自由组合

题目:给定一个仅包含数字 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用来确定应该是第几个字符

posted @ 2018-11-15 10:48  不想取名字所以就随便写了  阅读(199)  评论(0编辑  收藏  举报