题目要求
给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。
给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。
示例 1:
输入:digits = "23"
输出:["ad","ae","af","bd","be","bf","cd","ce","cf"]
示例 2:输入:digits = ""
输出:[]
示例 3:输入:digits = "2"
输出:["a","b","c"]
提示:
0 <= digits.length <= 4
digits[i] 是范围 ['2', '9'] 的一个数字。来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/letter-combinations-of-a-phone-number
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
这个题目乍一看很晦涩,但是理解题目后会发现跟之前一篇讲回溯法的类似,下面我们便开始进行讲解。
题目理解以及思路分析
(一) 首先先仔细阅读题目,先理解什么是回溯
顾名思义,通过一次一次尝试或者结果的办法。按照条件往下执行,以达到目标。当某一步不符,或者达不到目标时,回到前一次,尝试其余的可能。这种路走不通就退回走其他的的方法就称为回溯法。
(二) 理解了什么是回溯后,我们接着往下看
先要科普下,排列和组合的含义:
排列:有序排列的元素的集合。
组合:不管排列顺序的集合。
通过举例来了解组合排列:
排列举例:如1,2 ,3的排列方法A3_3 = 3! = 3 * 2 * 1 = 6种
组合举例:如1,2,3的组合方法 C3_3 = 1种
那么这里是排列问题:
1,2 ,3的全排序需要做才能计算出来。
不妨不用数学的方法来思考:
下标[0]1 -> [1]2 -> [2]3
第一步 每次固定一个数字在 [0]下标处,问题就从3!-> 3 * 2!
第二部 每次固定一个数字在 [1]下标处,问题就从3!-> 321
重复步骤1和步骤2,就能等到所有的结果。
相信这样读者们就已经对这道题目有了很好的理解和掌握
下面我们进行代码部分的讲解
代码讲解
// 转化电话按键 char *word[] = { "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz" }; void backTracK(char *digits, int *returnSize,char **returnStr,int index,char *stack,int top) { int len = strlen(digits); if(top >= len) { returnStr[*returnSize] =(char *)malloc( sizeof(char ) * (top + 1)); memcpy(returnStr[*returnSize] ,stack,sizeof(char) * top); returnStr[*returnSize][top] = '\0'; *returnSize = *returnSize + 1; return; } else { char *pWord = word[ digits[index]-'2']; //索引字符串 int indexLen = strlen(pWord); //候选字符串的长度 int i; for(i =0; i < indexLen; i++) { stack[top] = pWord[i]; backTracK(digits,returnSize,returnStr,index + 1,stack,top+1); } } } char **letterCombinations(char *digits, int *returnSize) { *returnSize = 0; int len = strlen(digits); if (digits == NULL || len == 0) { return NULL; } int maxLen = pow(4,len); char **returnStr = (char **)malloc(maxLen * sizeof(char *)); memset(returnStr, 0, maxLen * sizeof(char *)); char *pWord = word[ digits[0]-'2']; //索引字符串 int indexLen = strlen(pWord); //候选字符串的长度 int i; char stack[4] = {0}; for(i =0; i < indexLen; i++) { stack[0] = pWord[i]; backTracK(digits,returnSize,returnStr,1,stack,1); } return returnStr; }
// 转化电话按键 char *word[] = { "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz" };
这部分很好理解,就是为下面的运作做铺垫
void backTracK(char *digits, int *returnSize,char **returnStr,int index,char *stack,int top) { int len = strlen(digits); if(top >= len) { returnStr[*returnSize] =(char *)malloc( sizeof(char ) * (top + 1)); memcpy(returnStr[*returnSize] ,stack,sizeof(char) * top); returnStr[*returnSize][top] = '\0'; *returnSize = *returnSize + 1; return; } else { char *pWord = word[ digits[index]-'2']; //索引字符串 int indexLen = strlen(pWord); //候选字符串的长度 int i; for(i =0; i < indexLen; i++) { stack[top] = pWord[i]; backTracK(digits,returnSize,returnStr,index + 1,stack,top+1); } } }
这一部分其实也比较简单,具体的方法还是之前的回溯,建议不太明白的读者可以看看之前几篇文章的讲解。
总结
本题的大致思路还是回溯法,这是一个经典的算法,这样的算法可以使得程序变得更简洁,运行的更快。