[算法题解详细]回溯法解力扣17电话号码的字母组合

题目

给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。

给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。
[算法题解详细]回溯法解力扣17电话号码的字母组合_第1张图片
示例 1:

输入:digits = "23"
输出:["ad","ae","af","bd","be","bf","cd","ce","cf"]

示例 2:

输入:digits = ""
输出:[]

示例 3:

输入:digits = "2"
输出:["a","b","c"]

提示:

 1. 0 <= digits.length <= 4
 2. digits[i] 是范围 ['2', '9'] 的一个数字。

思路

看到这个题目的第一感觉就是会觉得很麻烦,题目给出digits数组是一个仅包含2-9数字的字符串,同时2-9数字又代表了电话按键上相应的几个字符串,这里我们可以开一个string数组letter用来保存2-9数字代表的分别是哪些字符串,同时为了防止下标不对应,我们需要给0,1下标给上一个空字符串或者是随便一个字符,因为我们使用的下标也只有2-9,并不会使用到0,1下标,但是以防万一我们还是给上空字符串要好一些。

然后我们看示例会发现digits数组中有几个数字,那么答案就是这几个数字代表的那几个字符串每个字符串取一个字符得出的排列,顺序就是按digits数组给出的数字顺序来,这时候会有人疑惑,digits数组给出的字符串长度是变化的,也就是数字个数从0-8都可能会有,如果是两个数字两层循环就够了,八个数字就要八层循环,

那么如何来动态改变循环层数呢?

这里就是dfs的使用了,同时也是递归,我们通过给dfs函数传参,然后通过参数来动态控制循环层数,达到题目指定的层数,也就是digits数组的长度就直接终止递归,这样就实现了动态控制循环层数了。

然后是字符的组合,就需要我们用到回溯法了,接下来我们看代码

代码

首先在主函数中,我们要初始化ans容器,用来存储答案,并且要定义好letter数组,用来保存下标2-9对应的字符串
还要定义一个temp字符串,用来保存每一个字符串组合
注意这里我们要对digits数组判空,如果是空的我们需要直接返回初始化的ans容器

class Solution {
public:
    int n;
    string letter[10] = {"", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"};
    vector<string> ans;
    string temp;
    vector<string> letterCombinations(string digits) {
        n = digits.length();
        ans.clear();
        if(digits.length() == 0) {
            return ans;
        }
        dfs(digits, 0);
        return ans;
    }
};
dfs函数中,出口条件还是当递归层等于了digits数组的长度时,我们将当前temp保存的字符串组合加入ans容器中,因为我们在dfs中设置的条件,会让只要是递归到了这一层的temp就是一定满足答案的字符串组合,加入容器后我们直接终止当前递归,回溯到上一层递归,寻找其他可行的字符串组合
void dfs(string& digits, int u) {
     if(u == n) {
         ans.push_back(temp);
         return;
     }
}

在这里我们要注意digits数组是一个字符串,所以我们取每一位字符的时候需要转为数字才能直接使用为下标,将字符转为数字的方法有很多,我这里是直接**-'0’字符转成数字**,然后在每一次递归中我们都要循环一遍当前的letter下标为digits[u]数字的字符串,来进行组合,这里要注意回溯的应用,就是temp在下一层递归前添加当前选中的字符,在下一层递归完成后,我们需要回到添加字符前的那一步,方便寻找其他的可行的组合

void dfs(string& digits, int u) {
     if(u == n) {
         ans.push_back(temp);
         return;
     }
     int t = digits[u] - '0';
     for(int i = 0; i < letter[t].length(); i++) {
         if(u + 1 > n) {
             return;
         }
         temp += letter[t][i];
         dfs(digits, u + 1);
         temp = temp.substr(0, temp.length() - 1);
     }
} 

这里加了一个u+1是防止越界的,同时也相当于一个剪枝
下面是完整代码:

class Solution {
public:
    int n;
    string letter[10] = {"", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"};
    vector<string> ans;
    string temp;
    void dfs(string& digits, int u) {
        if(u == n) {
            ans.push_back(temp);
            return;
        }
        int t = digits[u] - '0';
        for(int i = 0; i < letter[t].length(); i++) {
            if(u + 1 > n) {
                return;
            }
            temp += letter[t][i];
            dfs(digits, u + 1);
            temp = temp.substr(0, temp.length() - 1);
        }
    }
    vector<string> letterCombinations(string digits) {
        n = digits.length();
        ans.clear();
        if(digits.length() == 0) {
            return ans;
        }
        dfs(digits, 0);
        return ans;
    }
};

大家好我是程序员云锦,致力于前端和算法方向,希望大家可以多多支持我,目前我正在坚持每日刷题中,感兴趣的你可以和我一起同步刷题哦!

你可能感兴趣的:(算法与数据结构知识,算法,leetcode,dfs)