leetcode----17.电话号码的字母组合(回溯和队列两种解法)

17.电话号码的字母组合(回溯算法)

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

给出数字到字母的映射如下(与电话按键相同 拼音九键)。注意 1 不对应任何字母。

思路:

  • 方法一:回溯
  • 第一时间想到的是使用for循环嵌套来解决,但是发现输入数组不固定(这种情况下应该使用回溯算法–也就是递归)。但是可以发现for循环嵌套的层数取决于输入字符串digits的个数。对于输入字符串23,本质就是求2和3对应字符的排列组合,可以将问题抽象为遍历下面这颗决策树,记录到每个叶子节点的路径。此时需要考虑三个问题:
    • 路径:也就是已经做出的选择。
    • 选择列表:也就是你当前可以做的选择。
    • 结束条件:也就是到达决策树底层,无法再做选择的条件。
      leetcode----17.电话号码的字母组合(回溯和队列两种解法)_第1张图片
class Solution {
    public List<String> letterCombinations(String digits) {
        List<String> combinations = new ArrayList<String>();
        if (digits.length() == 0) {
            return combinations;
        }
        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");
        }};

        StringBuffer sb = new StringBuffer();
        dfs(phoneMap, combinations, digits, 0, sb);
        return combinations;
    }

    public void dfs(Map<Character, String> phoneMap, List<String> combinations, String digits, int index, StringBuffer res){
        //回溯结束条件
        if(index == digits.length()){
            //加入路径
            combinations.add(res.toString());
        } else {
            char number = digits.charAt(index);
            String dict = phoneMap.get(number);
            //选择列表
            for(int i = 0; i < dict.length(); i++){
                char ch = dict.charAt(i);
                //做选择
                res.append(ch);
                //
                dfs(phoneMap, combinations, digits, index + 1, res);
                //撤销选择
                res.deleteCharAt(index);
            }
        }
    }
}
  • 方法二:使用队列实现,感觉类似于层序遍历(bfs)参考上面决策树,每次队列中只存放到这层节点的路径,具体步骤如下图。

以输入字符串"23"为例,首先需要在队列中添加一个元素 相当于这棵树的根节点,到根节点的路径为空。然后将到根节点路径出队(即最先入队的空字符串,注意队列中只存放到这层节点的路径),"2"对应的字符(对应决策树第二层节点)直接放入队列,因为从根节点到第二层节点的路径就是节点本身,比如:"" + 'a' = "a"。接下来是第三层,参考上面的决策树,我们知道第二层的每个节点的所有孩子对应”3“表示的所有字符,所以到第三层节点的路径就是"2"和”3“对应字符的组合,即出队"a"分别与{“d”, “e”, “f”}(3对应的字符)组成{“ad”, “ae”, “af”}并依次入队作为从节点"a"到其孩子节点的路径,“b”,"c"节点同理。其他情况类似。

class Solution {
    public List<String> letterCombinations(String digits) {
        List<String> combinations = new ArrayList<String>();
        if (digits.length() == 0) {
            return combinations;
        }
        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");
        }};

        Queue<String> queue = new LinkedList<>();
        //首先需要在队列中添加一个元素  相当于这棵树的根节点,到根节点的路径为空。
        queue.offer("");
        StringBuffer sb = new StringBuffer();
        for(int i = 0; i < digits.length(); i++){
            String dict = phoneMap.get(digits.charAt(i));
            int size = queue.size();
            while(size > 0) {
                sb.append(queue.poll());
                for(int j = 0; j < dict.length(); j++){
                    sb.append(dict.charAt(j));
                    queue.offer(sb.toString());
                    sb.deleteCharAt(i);
                }
                //清空StringBuffer
                sb.delete(0, sb.length());
                size--;
            }
        }

        //将队列中的组合存入list中并返回
        while(!queue.isEmpty()) {
            combinations.add(queue.poll());
        }

        return combinations;
    }
}

你可能感兴趣的:(#,leetcode,leetcode,算法,数据结构)