算法小白,最近刷LeetCode。希望能够结合自己的思考和别人优秀的代码,对题目和解法进行更加清晰详细的解释,供大家参考^_^
Letter Combinations of a Phone Number
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.
题目大意是:给定一个数字组成的字符串,其中每个数字字符都对应一个字符串,如数字2对应字符串“abc”,数字3对应字符串“def”,其实就是平常使用的九宫格输入法中的对应关系。现在需要按照数字出现的顺序给出所有可能的英文字母组合。
显然,所有的可能组合共计 4^i * 3^(n-i),其中n为输入数字串的长度,i为7和9两个数字出现的次数,n-i即为剩下数字的出现次数。由于1和0并没有对应任何的英文字母,不清楚具体该如何处理,好在实测发现,当字符串中出现1或0时,结果集都为空,这种情况提前处理一下就好了。
第一印象这个题需要用递归的方法,每次递归选取下一个字符串,顺序取出一个字符加到末尾,直到字符长度满足要求,将其加入结果集中,函数返回。
直接上代码:
class Solution {
public:
// 备选字符串集合,共计8个,坐标0-7分别对应数字字符2-9
string str_arr[8] = {
"abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"
};
// 递归函数,参数较多,是为了方便自己理解,下面一个个解释
// string str: 每次在该字符串末尾加入字符,直到其长度等于digits的长度
// const int &len :digits字符串长度,也是最终结果集中每个字符串的长度,这里声明为常量引用
// const string &digits :输入的数字串,同样声明为常量引用
// int pos :指定当前递归使用哪个候选集,如pos=2,即使用digits中第3个数字对应的字符串作为候选集
// vector<string> &vs :结果集,声明为引用
void fun(string str, const int &len, const string &digits, int pos, vector<string> &vs){
if (len == str.length()) vs.push_back(str); // 长度==len,加入结果集,本次递归结束
else {
string tmp = str_arr[digits[pos] - '0' - 2]; // 指定候选集
++pos; // 指定下一次使用的数字在digits中的位置
for (int i = 0; i < tmp.length(); ++i) { // 顺序在str的末尾增加一个字符,并递归
fun(str + tmp[i], len, digits, pos, vs);
}
}
}
vector<string> letterCombinations(string digits) {
int len = digits.length();
vector<string> vs;
// 处理空串和包含0或1的情况,返回空结果集
if (0 == len) return vs;
for (int i = 0; i < len; ++i)
if (digits[i] == '0' || digits[i] == '1') return vs;
// 调用递归函数,第一个str为空,pos为0
fun(string(""), len, digits, 0, vs);
return vs;
}
};
我自身对递归程序的编写不是很熟练,5个参数也是我根据一步步的思考加上去的,可能存在冗余,比如pos和len。第一次完成后,也是手动分析了一下递归过程,修改了其中两个主要错误之后,才到上述的样子。
看了别人的代码,也有非递归的方法,暂时先不介绍了,等我回头复习的时候再仔细研究下。