17. Letter Combinations of a Phone Number
Given a string containing digits from 2-9
inclusive, return all possible letter combinations that the number could represent. Return the answer in any order.
A mapping of digits to letters (just like on the telephone buttons) is given below. Note that 1 does not map to any letters.
Example 1:
Example 2:
Example 3:
Constraints:
0 <= digits.length <= 4
digits[i]
is a digit in the range['2', '9']
.
Solution:
回溯三问:
- 当前操作? 枚举path[i] 要填入的字母
- 子问题? 构造字符串 >= i的部分
- 下一个子问题? 构造字符串 >= i + 1的部分
dfs(i) -> dfs(i + 1)
class Solution {
public List<String> letterCombinations(String digits) {
List<String> combinations = new ArrayList<>();
if (digits.length() == 0){
return combinations;
}
Map<Character, String> letters = Map.of(
'2', "abc",
'3', "def",
'4', "ghi",
'5', "jkl",
'6', "mno",
'7', "pqrs",
'8', "tuv",
'9', "wxyz"
);
backtrack(0, new StringBuilder(), digits, letters, combinations);
return combinations;
}
private void backtrack(int index, StringBuilder sb, String digits, Map<Character, String> letters, List<String> combinations){
if (sb.length() == digits.length()){
combinations.add(sb.toString());
return;
}
String possibleLetters = letters.get(digits.charAt(index));
for (char letter : possibleLetters.toCharArray()){
sb.append(letter);
backtrack(index + 1, sb, digits, letters, combinations);
sb.deleteCharAt(sb.length() - 1);
}
}
}
// TC: O(branch^level) = O(k^n) = O(4^n)
// SC: O(level) = O(n)
DFS vs Backtrack
区别分析:
- Terminology(术语上的区别): - 上面的代码看似是 Backtracking 实现,实际上在某种程度上也可以被称为 DFS。这两者的差别更多在于问题类型和如何优化搜索,而不是在具体的实现细节上。 - DFS 更偏向于一种遍历方式,而 Backtracking 通常用于特定类型的问题,如组合问题、排列问题,且它会在无效的路径上做剪枝(通过回溯避免无效的搜索)。
- 搜索方式: - DFS 是沿着一条路径走到底再回溯,一般不做复杂的判断(只是在目标找到时结束)。 - Backtracking 则会在某些路径不符合条件时提前结束搜索(比如数独、N皇后问题中发现某个选择导致解无效,就会提前回溯)。
代码上的区别:
- DFS 版本通常不强调剪枝机制,更多的是简单地递归遍历所有可能的路径。
- Backtracking 版本则会在递归的过程中进行选择,并且通常带有“撤销选择”(即回溯)的机制。
综上,DFS 和 Backtracking 在实现上的区别其实并不大,都是通过递归进行深度搜索。在具体问题中,Backtracking 更强调“尝试 + 回溯”的过程,而 DFS 只是单纯地进行深度遍历。