Given a digit string, return all possible letter combinations that the number could represent.
A mapping of digit to letters (just like on the telephone buttons) is given below.
Input:Digit string "23" Output: ["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"].
Note:
Although the above answer is in lexicographical order, your answer could be in any order you want.
这道题很简单,只要遍历就可以了。但是我在Discuss区里看到一个挺有意思的解法,给大家分享一下。原解法请戳https://leetcode.com/discuss/101036/youll-regret-trick-solution-without-recursion-while-lines。
这里假设我们对每个数字代表的数字分别进行编号,那对于string "23"我们所得到的答案分别是 00,01,02,10,11,12,20,21,22。看到这里我想大家可能稍微会联想到一点东西。这些数字就像3进制的0到5。当然不失一般性的,如果我们将字母串转换成数字串,我们将可以得到N个数字串,它们的十进制值落在0到N-1中,而它们应该是一种“混合进制”表示。所以现在的问题就是如何将一个十进制的数字n转换成一个混合进制的数,当然我们知道每一位对应的进制应该为该位的数字对应的字母总数,如“23”中2应该是对应3进制,而3也应该是对应3进制。值得注意的是例如之前的"12"的值应该是1*3+2,其中1*3中的3来自“def”对应的3。这应该不难理解,1对应的权值来自低它一位的进制。
所以代码的核心部分,应该如下:
vector<string> solve(string s)
{
const char *num_letters[12] = {" ","","abc","def","ghi","jkl","mno","pqrs","tuv","wxyz",};
const int lens[12] = { 1, 0, 3, 3, 3, 3, 3, 4, 3, 4,};
vector<string> aVec;
string::iterator ptr = s.begin();
for(;ptr!=s.end();ptr++)<span style="white-space:pre"> </span>//输入中有1时不能转换
if(*ptr=='1')
return aVec;
const int len = s.size();
int ansID = 0;
while(1)
{
int n = ansID++;
string str;
for(int i=len-1;i>=0;i--)
{
int tmp = s[i]-'0';
str = num_letters[tmp][n%lens[tmp]] + str;
n /= lens[tmp];
}
if(n) break;<span style="white-space:pre"> </span>//此时ansID >= N
aVec.push_back(str);
}
}