代码随想录 17. 电话号码的字母组合

123 阅读4分钟

17. 电话号码的字母组合 - 力扣(LeetCode)

image.png

本题的主要思路:映射->递归 ->回溯

说到“所有组合”我们就应该想到“回溯”,回溯的本质就是穷举,也就是可以把我们的所有组合打印出来。

所有的回溯都可以化为一个抽象的树状结构,画图很主要,方便我们理解

假设我们传入 “2 3” “2”实际上就是“a b c”,"3"实际上就是" d e f"

然后要求我们去列举所有可能,那我们可以先把取a,把a的所有可能列举,再取b,把b的所有可能列举,再取c,把c的所有可能列举:

image.png

然后就是我们收获结果的地方了,收获果实的地方在叶子节点。 image.png

ok,图画出来就好写了。

映射

题目给我们穿了一个string的变量digits,假设figotis="2 3",要求我们返回" 2 3"映射的字母排列组合的所有可能

image.png 这个数的深度我们一般用递归来处理,因为递归是触底才结束。树的宽度就是子子集的宽度,我们通常用for循环来处理:

image.png

开始写代码: 我们可以通过二维数组映射,写一个数组:

vector<string> board = {"", "", "abc", "def", "ghi","jkl","mno","pqrs","tuv","wxyz"};

比如我们想访问 digits的“2” 那我们就board[index][i], index为2,i为0 1 2时可遍历 " a b c"

然后我们来写递归:

递归

void backstracking(int index,string digits)//digits=" 2  3"  index为下标,用来访问是"2" 还是"3"
{
}

先写回溯的结束条件,上文说过收获结果的地方在叶子节点,我们可以用一个容器来存放单个叶子节点:

image.png

string s

但是有多个叶子节点,所以还需要把所有的s放到一起

image.png

result.push_back(s);

我们把叶子节点遍历完就结束。

所以我们可以这样写回溯结束条件:

if(index == digits.size()) return result;

递归代码实现: digits=“ 2 3” 前面说过我们的映射是通过下标来映射,所以我们需要把“2 3”变为数组 2,数字3,这样就可以通过下标来访问了。

int num = digits[index] - '0'; //表示按到了键盘上的第几个键

然后我们先对2 进行递归,首先需要遍历一下abc,把abc分别取出来,也就是刚开始我们说的第二步:

for(int i=0;i<board[nums].size();i++
{
   s.push_back(board[num)[i]);
}

然后我们要接着往下递归,再往下递归就要从"d e f"的位置开始递归

image.png 我们注意到“ d e f”是“3”里面的,所以我们要访问"3":

backtracking(daigits,index+1)

回溯

此时s里面就有了“ a d”,我们访问到了底部,然后就是回溯的过程。

回溯的过程就是先把"d"弹出去,然后再递归获取“e”,然后再把“e”弹出去,再返回,再递归获取“f”。 image.png

code

class Solution {
public:
    string s;
    vector<string> board = {"", "", "abc", "def", "ghi","jkl","mno","pqrs","tuv","wxyz"};
    vector<string> result;
    
    void dfs(int index, string digits){
        if(index == digits.size()){
            result.push_back(s);
            return;
        }
        int num = digits[index] - '0'; //表示按到了键盘上的第几个键
        for(int i = 0; i < board[num].size(); i ++){
            s.push_back(board[num][i]);  
            dfs(index + 1, digits);  //递归下一层
            s.pop_back();      //回溯
        }
    }
   
    vector<string> letterCombinations(string digits) {//digits是传入的字符串数字,比如“23”
        if(digits.size() == 0) return {};//这一步很重要:当`digits`为空字符串时,`index`会等于`digits.size()`,然后进入`if`条件,把空字符串`s`添加到`result`中,这并不是我们想要的。
        dfs(0, digits);
        return result;
    }
};

第一次调用 dfs(0, "23"),栈内元素为 ["", "23"]
第二次调用 dfs(1, "3"),栈内元素为 ["a", "3"]
第三次调用 dfs(2, ""),栈内元素为 ["ad", ""]
第四次调用 dfs(2, ""),栈内元素为 ["ae", ""]
第五次调用 dfs(2, ""),栈内元素为 ["af", ""]
第六次调用 dfs(1, "3"),栈内元素为 ["b", "3"]
第七次调用 dfs(2, ""),栈内元素为 ["bd", ""]
第八次调用 dfs(2, ""),栈内元素为 ["be", ""]
第九次调用 dfs(2, ""),栈内元素为 ["bf", ""]
第十次调用 dfs(1, "3"),栈内元素为 ["c", "3"]
第十一次调用 dfs(2, ""),栈内元素为 ["cd", ""]
第十二次调用 dfs(2, ""),栈内元素为 ["ce", ""]
第十三次调用 dfs(2, ""),栈内元素为 ["cf", ""]