leetcode
leetcode 1 ~ 50
电话号码的字母组合

电话号码的字母组合

难度:

标签:

题目描述

给定一个仅包含数字 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'] 的一个数字。

代码结果

运行时间: 44 ms, 内存: 15 MB


/**
 * Problem: Given a string containing digits from 2-9, return all possible letter combinations that the number could represent.
 * Approach: Use Java Stream and recursive function to generate all possible combinations.
 */
 
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
 
public class Solution {
    // Mapping of digits to corresponding letters
    private static final String[] KEYPAD = {"", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"};
 
    public List<String> letterCombinations(String digits) {
        if (digits == null || digits.isEmpty()) {
            return List.of();
        }
        return letterCombinations(digits, 0).collect(Collectors.toList());
    }
 
    private Stream<String> letterCombinations(String digits, int index) {
        if (index == digits.length()) {
            return Stream.of("");
        }
        String letters = KEYPAD[digits.charAt(index) - '0'];
        return letters.chars()
                .mapToObj(c -> (char) c)
                .flatMap(letter -> letterCombinations(digits, index + 1).map(combination -> letter + combination));
    }
}

解释

方法:

这个题解使用回溯算法来解决电话号码的字母组合问题。首先,定义了一个字典 m,将数字映射到对应的字母。然后定义一个辅助函数 backtrack,它接受一个路径参数 path。在函数中,如果 path 的长度等于 digits 的长度,说明找到了一个完整的字母组合,将其加入答案列表 ans 中。否则,根据当前 path 的长度,从 digits 中取出对应的数字,并获取该数字对应的字母选择。遍历这些字母选择,将每个字母加入 path,递归调用 backtrack,然后在回溯时将该字母从 path 中移除。最后,在主函数中调用 backtrack([]),并返回答案列表 ans。

时间复杂度:

O(m^n * n)

空间复杂度:

O(m^n * n)

代码细节讲解

🦆
在回溯算法中,为什么在发现`path`的长度与`digits`的长度相等时,即认为找到了一个有效的字母组合?
在题目中,每个数字对应几个可能的字母,而`digits`代表了用户输入的数字序列。当`path`的长度与`digits`长度相等时,意味着已经为`digits`中的每个数字选择了一个对应的字母,形成了一个完整的字母组合。这种组合正好对应着`digits`输入的一个有效解释,即一个可能的字母组合。因此,这时可以认为找到了一个有效的字母组合,应当将其加入到答案列表中。
🦆
在`backtrack`函数中,为什么选择在递归后移除`path`中最后一个元素(即执行`path.pop()`)?这与回溯算法的哪个特性相关?
在`backtrack`函数中,`path.pop()`操作用于在每次递归调用后撤销前一个状态的选择,这是为了探索其他可能的字母选择,从而生成不同的字母组合。这一操作与回溯算法的特性`状态撤销`直接相关,它允许算法返回到上一个决策点,并试探其他可能的路径选择,从而全面搜索所有可能的解决方案。这种撤销和重新选择的过程是回溯算法解决组合和排列问题的核心机制。
🦆
字典`m`映射了数字到字母的关系,这种映射在算法中起到了什么作用?
字典`m`在算法中扮演了关键角色,它将每个数字映射到对应的一组字母上。这样,每当算法处理输入数字序列`digits`的某个数字时,可以直接通过这个映射找到该数字对应的所有可能的字母选择。这种映射简化了查找过程,提高了效率,并使得算法能够针对每个数字快速生成所有可能的字母组合。通过这种方式,`m`映射直接支持了算法的主要功能,即生成和探索所有基于输入数字的可能字母组合。

相关问题

括号生成

数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。

 

示例 1:

输入:n = 3
输出:["((()))","(()())","(())()","()(())","()()()"]

示例 2:

输入:n = 1
输出:["()"]

 

提示:

  • 1 <= n <= 8

组合总和

给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target ,找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 ,并以列表形式返回。你可以按 任意顺序 返回这些组合。

candidates 中的 同一个 数字可以 无限制重复被选取 。如果至少一个数字的被选数量不同,则两种组合是不同的。 

对于给定的输入,保证和为 target 的不同组合数少于 150 个。

 

示例 1:

输入:candidates = [2,3,6,7], target = 7
输出:[[2,2,3],[7]]
解释:
2 和 3 可以形成一组候选,2 + 2 + 3 = 7 。注意 2 可以使用多次。
7 也是一个候选, 7 = 7 。
仅有这两种组合。

示例 2:

输入: candidates = [2,3,5], target = 8
输出: [[2,2,2,2],[2,3,3],[3,5]]

示例 3:

输入: candidates = [2], target = 1
输出: []

 

提示:

  • 1 <= candidates.length <= 30
  • 2 <= candidates[i] <= 40
  • candidates 的所有元素 互不相同
  • 1 <= target <= 40

二进制手表

二进制手表顶部有 4 个 LED 代表 小时(0-11),底部的 6 个 LED 代表 分钟(0-59)。每个 LED 代表一个 0 或 1,最低位在右侧。

  • 例如,下面的二进制手表读取 "4:51"

给你一个整数 turnedOn ,表示当前亮着的 LED 的数量,返回二进制手表可以表示的所有可能时间。你可以 按任意顺序 返回答案。

小时不会以零开头:

  • 例如,"01:00" 是无效的时间,正确的写法应该是 "1:00"

分钟必须由两位数组成,可能会以零开头:

  • 例如,"10:2" 是无效的时间,正确的写法应该是 "10:02"

 

示例 1:

输入:turnedOn = 1
输出:["0:01","0:02","0:04","0:08","0:16","0:32","1:00","2:00","4:00","8:00"]

示例 2:

输入:turnedOn = 9
输出:[]

 

提示:

  • 0 <= turnedOn <= 10