Leecode 17 电话号码的字母组合

题目:

给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。
给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。

示例:
输入:“23”
输出:[“ad”, “ae”, “af”, “bd”, “be”, “bf”, “cd”, “ce”, “cf”].
在这里插入图片描述

说明:
尽管上面的答案是按字典序排列的,但是你可以任意选择答案输出的顺序。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/letter-combinations-of-a-phone-number
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

选择算法

这道题很明显是个排列组合问题,那么第一时间想到的就是:

  1. 递归
  2. 回溯
    这道题递归以及回溯都可以解决。这里讲解回溯的办法好了。

过程

  1. 选择合适的数据结构存储 数字与字符串的对应关系。 很明显这里需要使用map
    定义一个map
//初始化map
        Map<Character, String> map = new LinkedHashMap<>();
        map.put('2', "abc");
        map.put('3', "def");
        map.put('4', "ghi");
        map.put('5', "jkl");
        map.put('6', "mno");
        map.put('7', "pqrs");
        map.put('8', "tuv");
        map.put('9', "wxyz");
  1. 我们在过程中还需要维护一个字符串 tmp,表示已有的字母排列的嘛。
    每次进入回溯,就将当前的字符追加到 tmp后面, 当tmp的长度达到了方法输入字符串的长度就可以添加到结果集中去。
伪代码:
	List<String> ans = new LinkedList<>();
	if(tmp.length() == input.length()) {
            ans.add(sb.toString());
            return;
    }
  1. 回溯思想:tmp字符串初始为空。每次取电话号码的一位数字,从哈希表中获得该数字对应的所有可能的字母,并将其中的一个字母插入到已有的字母排列后面,然后继续处理电话号码的后一位数字,直到处理完电话号码中的所有数字,即得到一个完整的字母排列。然后进行回退操作,遍历其余的字母排列。

代码

class Solution {
    //结果集
    List<String> ans = new LinkedList<>();
    public  List<String> letterCombinations(String digits) {
        //特殊判断
        if(digits.length() == 0)
            return ans;
        //初始化map
        Map<Character, String> map = new LinkedHashMap<>();
        map.put('2', "abc");
        map.put('3', "def");
        map.put('4', "ghi");
        map.put('5', "jkl");
        map.put('6', "mno");
        map.put('7', "pqrs");
        map.put('8', "tuv");
        map.put('9', "wxyz");
        char[] chars = digits.toCharArray();
        StringBuilder sb = new StringBuilder();
        backtrace(0, map, chars, sb);
        return ans;
    }

    public  void backtrace(int index, Map<Character, String> map,char[] chars, StringBuilder sb){
        //如果sb的容量达到了digits的长度,代表这次回溯已经完成,存入结果集
        if(sb.length() == chars.length) {
            ans.add(sb.toString());
            return;
        }
        //获取当前数字对应的多个字符
        String s = map.get(chars[index]);
        for(int i = 0; i < s.length(); i++){
            //尝试加入当前数字对应的其中一个字符
            sb.append(s.charAt(i));
            //回溯
            backtrace(index + 1, map, chars, sb);
            //删除最后一个加入的字符,达到回溯的目的
            sb.deleteCharAt(sb.length() - 1);
        }
    }
}

思考

其实回溯算法有模板:

void fn(n) {

    // 第一步:判断输入或者状态是否非法?
    if (input/state is invalid) {
        return;
   }
    // 第二步:判读递归是否应当结束?
    if (match condition) {
        return some value;
   }

    // 遍历所有可能出现的情况
    for (all possible cases) {
  
        // 第三步: 尝试下一步的可能性
        solution.push(case)
        // 递归
        result = fn(m)

        // 第四步:回溯到上一步
        solution.pop(case)
    
    }
    
}

掌握到了这种思路 每次遇到这种题就会觉得很简单了。


更新递归办法:

class Solution {
    List<String> ans = new LinkedList<>();
    public   List<String> letterCombinations(String digits) {
        //特殊判断
        if(digits.length() == 0)
            return ans;
        //初始化map
        Map<Character, String> map = new LinkedHashMap<>();
        map.put('2', "abc");
        map.put('3', "def");
        map.put('4', "ghi");
        map.put('5', "jkl");
        map.put('6', "mno");
        map.put('7', "pqrs");
        map.put('8', "tuv");
        map.put('9', "wxyz");
        char[] chars = digits.toCharArray();
        StringBuilder sb = new StringBuilder();

        //递归办法  s初始化为 ""
        recursion(chars, map, 0, "");

        //backtrack(0, map, chars, sb);
        return ans;
    }

    public  void recursion(char[] chars, Map<Character, String> map, int index, String s){
    	//长度达到所求字符串长度之后,即可加入到结果List中
        if(s.length() == chars.length){
            ans.add(s);
            return;
        }
        //获取当前位置数字所对应的所有字符 (2 - "abc")
        String tmp = map.get(chars[index]);
        //递归尝试各种符合的字符
        for(int i = 0; i < tmp.length(); i++){
        	//递归  当前数组为2,去对应tmp中的"a",那么 s就更新为 s + "a"
        	//index + 1 是为了与下一个数组对应的字符串中的字符进行尝试
            recursion(chars, map, index + 1, s + tmp.charAt(i));
        }
    }
}

递归算法效率:
在这里插入图片描述
回溯算法效率:
在这里插入图片描述

相比较而言,递归方法效率比回溯低下不少。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值