好的,让我们逐行分析这段代码,并详细说明运行步骤和思路。你的目标是根据一个字符串数字,生成所有可能的字母组合。每个数字对应一组字母,类似于电话键盘上的映射。
代码解析与思路:
class Solution {
public:
vector<string> ans; // 用于存储所有生成的字母组合
vector<string> letterCombinations(string digits) {
vector<string> mapping = {"abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"};
string s; // 用于存储当前递归路径中的字母组合
combinations(mapping, digits, s, 0); // 调用递归函数来生成字母组合
if (digits.empty()) return {}; // 如果输入的数字为空,直接返回空
return ans; // 返回最终结果
}
void combinations(const vector<string>& mapping, const string& digits, string s, int n) {
if (n == digits.size()) { // 当递归到达最后一位数字时,说明生成了一个完整的字母组合
ans.push_back(s); // 将当前字母组合添加到答案中
return; // 返回,结束递归
}
// 获取当前数字对应的字母集
int digit = digits[n] - '2'; // '2' -> 0, '3' -> 1, ..., '9' -> 7
// 对当前数字对应的字母集进行遍历
for (int i = 0; i < mapping[digit].size(); i++) {
s.push_back(mapping[digit][i]); // 将当前字母添加到字母组合中
combinations(mapping, digits, s, n + 1); // 递归处理下一个数字
s.pop_back(); // 回溯,移除最后添加的字母,准备处理下一个字母
}
}
};
思路:
1. 映射表:mapping 数组存储了每个数字对应的字母集。digits[n] 可以通过 digits[n] - '2' 来映射到 mapping 中对应的字母集。例如,数字 2 对应 “abc”,数字 3 对应 “def”,依此类推。
2. 递归回溯:递归地从第一个数字开始,每次选择该数字对应的一个字母,拼接到当前的字母组合 s 中。每次选择完一个字母后,递归到下一个数字的位置,直到生成一个完整的字母组合。
3. 回溯:当递归进入一个分支后,通过 s.pop_back() 回到之前的状态,继续尝试其他字母。这是典型的回溯法应用。
4. 递归的终止条件:当递归深度等于 digits 的长度时,表示已经拼接出了一个完整的字母组合,将其添加到结果中。
5. 空输入处理:如果输入的 digits 为空,直接返回空结果。
详细的运行步骤:
假设我们传入字符串 digits = "23"。
1. 初始化
• mapping = {"abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"}
• digits = "23"
• s = ""(用于存储当前字母组合)
• n = 0(当前递归的位置)
2. 第一次递归调用 combinations(mapping, "23", "", 0)
• n == 0,表示正在处理数字 2。
• 对应的字母集为 "abc",即需要依次添加 ‘a’, ‘b’, ‘c’。
• 进入第一个字母 ‘a’。
3. 第二次递归调用 combinations(mapping, "23", "a", 1)
• n == 1,表示正在处理数字 3。
• 对应的字母集为 "def",即需要依次添加 ‘d’, ‘e’, ‘f’。
• 进入第一个字母 ‘d’。
4. 第三次递归调用 combinations(mapping, "23", "ad", 2)
• n == 2,已经到达 digits 的末尾,生成了字母组合 "ad"。
• 将 "ad" 添加到结果中:ans = ["ad"]。
• 回溯:移除 ‘d’,继续尝试 ‘e’ 和 ‘f’。
5. 第四次递归调用 combinations(mapping, "23", "ae", 2)
• 生成字母组合 "ae",将其添加到结果中:ans = ["ad", "ae"]。
• 回溯:移除 ‘e’,继续尝试 ‘f’。
6. 第五次递归调用 combinations(mapping, "23", "af", 2)
• 生成字母组合 "af",将其添加到结果中:ans = ["ad", "ae", "af"]。
• 回溯:移除 ‘f’,返回到上一级递归。
7. 第六次递归调用 combinations(mapping, "23", "b", 1)
• 类似地,生成字母组合 "bd", "be", "bf",将它们依次添加到结果中:ans = ["ad", "ae", "af", "bd", "be", "bf"]。
8. 第七次递归调用 combinations(mapping, "23", "c", 1)
• 生成字母组合 "cd", "ce", "cf",将它们添加到结果中:ans = ["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"]。
9. 递归结束,返回结果 ans = ["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"]。
主要优点:
1. 清晰的递归结构:递归解决了多层嵌套的问题,每次递归都处理一个数字,并且生成所有可能的字母组合。
2. 回溯法:通过回溯机制移除已经处理过的字母,确保每次递归都能正确尝试所有可能的字母。
总结:
这段代码使用回溯法来解决问题,逐步生成每个可能的字母组合。当递归到最后时,完成一个组合并将其加入结果。通过回溯来管理递归树的状态,确保不遗漏任何可能的字母组合。