咱们继续按照分类来肝leetcode回溯分类下的题目,一直按照同一个分类来刷,比较容易养成自己的规则。
今天的题目是17. 电话号码的字母组合 :https://leetcode-cn.com/problems/letter-combinations-of-a-phone-number/
题意
给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。
给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。
思路推演
看到这道题应该可以想到咱们第一篇回溯文章《黑板上排列组合你舍得解开吗?》中的组合。这道题拨开花里胡哨的外表就是从给定的数组里面选数组,进行组合。
如果给定的数字是“23”,那么就是从给定的两个数组[a,b,c]和[d,e,f]中各选一个数组看有多少种组合而已。到这里,一旦发现是排列组合的题目我们都可以通过回溯,也就是深度优先遍历拿到他所有的可能性,再配合有规则的剪枝,我们就可以得到最终的答案了。
使用回溯来解决问题,那们就不墨迹了,直接上最开始的框架。
选择与回退:从数字对应的列表里选择一个字符,然后递归遍历下一个数字对应的情况。当递归完下一个字符的情况的时候再回到这一层,回到本层遍历其他字符。 终止条件:选择的列表长度等于给定数字的个数的时候代表选择完成。 过滤条件:这道题里面走得每一步都是唯一的,不需要过滤条件。
因为这道题只给到了数字部分,我们还是需要手动初始化一下数组,一遍我们后续的工作。
最后还需要注意下边界条件,如果传一个空串则需要返回一个空列表。
最后见如下代码,以及注释。
class Solution {
List<List<String>> digitsList = new ArrayList<>();
List<String> res = new ArrayList<>();
public List<String> letterCombinations(String digits) {
//边界条件
if(digits == null || digits.isEmpty()) {
return res;
}
//初始化数字和字母的对应列表,直接使用下标来代表数字。
digitsList.add(new ArrayList<>());
digitsList.add(new ArrayList<>());
digitsList.add(Arrays.asList("a", "b", "c"));
digitsList.add(Arrays.asList("d", "e", "f"));
digitsList.add(Arrays.asList("g", "h", "i"));
digitsList.add(Arrays.asList("j", "k", "l"));
digitsList.add(Arrays.asList("m", "n", "o"));
digitsList.add(Arrays.asList("p", "q", "r", "s"));
digitsList.add(Arrays.asList("t", "u", "v"));
digitsList.add(Arrays.asList("w", "x", "y", "z"));
dfs(digits, 0, "", res);
return res;
}
private void dfs(String digits, int index, String path, List<String> res) {
//终止条件
if(path.length() == digits.length()) {
res.add(new String(path));
return;
}
int num = Integer.valueOf(digits.substring(index, index + 1));
//根据数字遍历这个数字对应字符的列表
for(int i = 0; i < digitsList.get(num).size(); i++) {
String digit = digitsList.get(num).get(i);
//选择以及回退
path += digit;
dfs(digits, index + 1, path, res);
path = path.substring(0, path.length() -1);
}
}
}
最后
打完收工。明天继续搞回溯分类下的题目leetcode79:https://leetcode-cn.com/problems/word-search/,继续巩固回溯套路。一起刷题的朋友可以先看下题意了解一下。
欢迎关注公众号【理解并背诵君】,让我们一起开心刷题。