Leetcode每日一题--17. 电话号码的字母组合

68 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第25天,点击查看活动详情

前言

算法的重要性不言而喻!区分度高!

现在学习的门槛低了,只有能上网每个人都可以学编程!培训班6个月就可以培养出来能干活的人,你怎么从这些人中脱颖而出?没错!就是学算法,学一些底层和基础的东西。

说的功利点是为了竞争,卷死对手。真心话说就是能提高自己的基础能力,为技术可持续发展做好充分的准备!!!

提前入门学习书籍:CPrimerPlus、大话数据结构

image-20220705103735001

刷题网站

代码随想录 (programmercarl.com)

leetcode

我是按照代码随想录提供的刷题顺序进行刷题的,大家也可以去刷leetcode最热200道,都可以

刷题嘛,最重要的就是坚持了!!!

画图软件

OneNote

这个要经常用,遇见不懂的流程的话就拿它画一画!

笔记软件

Typoral

题目

leetcode.cn/problems/le…

image.png

解析

回溯三部曲:

  • 确定回溯函数参数

首先需要一个字符串s来收集叶子节点的结果,然后用一个字符串数组result保存起

再来看参数,参数指定是有题目中给的string digits,然后还要有一个参数就是int型的index。

这个index是记录遍历第几个数字了,就是用来遍历digits的(题目中给出数字字符串),同时index也表示树的深度。

//设置全局列表存储最后的结果
List<String> list = new ArrayList<>();
//每次迭代获取一个字符串,所以会设计大量的字符串拼接,所以这里选择更为高效的 StringBuild
StringBuilder temp = new StringBuilder();
public void backTracking(String digits, String[] numString, int num) {}
  • 确定终止条件

例如输入用例"23",两个数字,那么根节点往下递归两层就可以了,叶子节点就是要收集的结果集。

那么终止条件就是如果index 等于 输入的数字个数(digits.size)了(本来index就是用来遍历digits的)。

然后收集结果,结束本层递归。

代码如下:

求字符串的长度是length,求数组的长度是size()

if (index == digits.length()) {
    result.add(temp.toString);
    return;
}
  • 确定单层遍历逻辑

1.首先要取index指向的数字,并找到对应的字符集(手机键盘的字符集).因为数字都是字符串类型的所以要将字符串类型的数字转化为数字类型,通过得到的字符串数字减去字符串0即可!( ‘1’的对应编码是49的二进制码,'0'对应的是48,所以'1' - '0' = 1),得到数字之后再去numString取出数字对应的字母

2.遍历这个字符串

先把第一个字符加入临时数组中,之后通过递归再添加另一个数字对应的字母集在进行拼接,直到拼接的字符串个数等于数字的长度了就把临时数组的结果放到最终结果数组里.这个过程完成之后,就是回溯的过程.

回溯会把末尾的字母删除继续匹配

//str 表示当前num对应的字符串
String str = numString[digits.charAt(num) - '0'];
for (int i = 0; i < str.length(); i++) {
    temp.append(str.charAt(i));
    //c
    backTracking(digits, numString, num + 1);
    //剔除末尾的继续尝试
    temp.deleteCharAt(temp.length() - 1);
}

完整代码如下:

不好理解,就手动Debug一下或者手动模拟一下!

或者去力扣官网看那个官方的解法,有动态图还是很好理解的!

class Solution {
    public List<String> letterCombinations(String digits) {
        //结果数组combinations
        List<String> combinations = new ArrayList<String>();
        
        //digits是数字的字符串
        if (digits.length() == 0) {
            return combinations;
        }
        
        //phoneMap用来存放全部的数字对应的字符串
        Map<Character, String> phoneMap = new HashMap<Character, String>() {{
            put('2', "abc");
            put('3', "def");
            put('4', "ghi");
            put('5', "jkl");
            put('6', "mno");
            put('7', "pqrs");
            put('8', "tuv");
            put('9', "wxyz");
        }};
        
        //通过递归遍历
        backtrack(combinations, phoneMap, digits, 0, new StringBuffer());
        return combinations;
    }
​
    //index为遍历到的字符个数
    public void backtrack(List<String> combinations, Map<Character, String> phoneMap, String digits, int index, StringBuffer combination) {
        //到达叶子结点,收集到combinations结果数组里面
        if (index == digits.length()) {
            combinations.add(combination.toString());
        } else {
            //取digits是数字的字符串中的第一个字符
            char digit = digits.charAt(index);
            //获得第一个字符串对应的所有字母
            String letters = phoneMap.get(digit);
            //获取字母的长度
            int lettersCount = letters.length();
            //遍历这些字母
            for (int i = 0; i < lettersCount; i++) {
                //
                combination.append(letters.charAt(i));
                backtrack(combinations, phoneMap, digits, index + 1, combination);
                combination.deleteCharAt(index);
            }
        }
    }
}