电话号码的字母组合[LeetCode-17]

875 阅读3分钟

题目描述

思路分析

迭代法(或者叫做宽度有限搜索)

最外层循环遍历给定的源串,比如"234",比如遍历到第一个字符2,对应的字符串为"abc"
进入第二层循环,先得出当前已得到的res的长度,这一步最关键,详细说明如下:
设定一个变量vector res{""}用来存储最终的结果;初始为空字符串,很关键,这样在遍历第一个字符2的时候,会将2对应的每一个子串写入到res中,此时res为{"a","b","c"}。当继续遍历第二个字符3的时候,先求得res的长度为3,这样可以遍历到每一个子串"a", "b", "c",然后拿每一个子串去与当前的3对应"def"依次相加(这是第三层循环),得到新的子串集合,{"ad","ae","af","bd","be","bf","cd","ce","cf"},即为更新之后的res。后面的以此类推。

迭代法代码实现

class Solution {
public:
    vector<string> letterCombinations(string digits) {
        if (digits.empty()) {
            return vector<string>{};
        }
        vector<string> dict {"", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"};
        vector<string> res {""}; // 最开始设为只有一个空字符串的集合
        for (int i = 0; i < digits.size(); i++) {
            string cur_str = dict[digits[i] - '0']; // 比如"abc"

            vector<string> res2; // 为了重新求得一个字符串集合,再替换原来的字符串集合
            for (int j = 0; j < res.size(); j++) {
                string tmp = res[j];
                for (int k = 0; k < cur_str.size(); k++) {
                    res2.push_back(tmp + string(1, cur_str[k]));
                }
            }
            res = res2;
        }
        return res;
    }
};

深度优先搜索法

顾名思义,深度优先即,比如digits为"234",2->"abc", 3->"def", 4->"ghi",则深度搜索会先得到adg,adh,adi,然后得到aeg,aeh,aei也就是先以最后一个数字对应的字符完整遍历一遍,与上面的思路相反。
最核心的地方在于DFS函数的中止条件 level == digits.size() 这表示一次遍历的结束,得到了一个完整的结果集中的一个子串,然后进入下一次遍历。具体参考代码注释。

深度优先代码实现

class Solution {
public:
    vector<string> letterCombinations(string digits) {
        vector<string> res;
        if (digits.empty()) return res;

        string dict[] = {"abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"};
        DFS(digits,dict,0,"",res);
        return res;
    }

    // 参数digits为源串,disc为对应的字典,level即为当前走到的数字的index,out为当前已累积的子串,res为最终结果
    void DFS(string digits, string dict[], int level, string out, vector<string>& res){
        // 走到这里说明一次遍历结束,比如源串为"234",则走到了4对应的字符"ghi"中的某一个,函数返回,继续遍历ghi中的
        // 下一个字符
        if (level == digits.size()) {
            res.push_back(out);
            return;
        } else {
            //找到当前的数字(2~9)对应的stirng("abc"~"wxyz")
            string str = dict[digits[level]-'2'];
            for (int i = 0; i < str.size(); i++)
            {
                // 假设源串为"234",且当前走到了4,且i为0,即str[i]为g,此时out为"adg",于是进入DFS函数,
                // 因为level==digits.size(),res 添加了一个adg,然后执行out.pop_back(),这时候out为"ad"
                // 当i为1时,out变为"adh",然后DFS又返回,使得res添加一个adh,然后执行out.pop_back(),这时候
                // out变为"ad",然后i为2时。。。
                out.push_back(str[i]);
                DFS(digits, dict, level+1, out, res);
                out.pop_back();
            }
        }
    }
};