@@ -25,6 +25,7 @@ https://leetcode-cn.com/problems/letter-combinations-of-a-phone-number
2525## 前置知识
2626
2727- 回溯
28+ - 笛卡尔积
2829
2930## 公司
3031
@@ -33,7 +34,9 @@ https://leetcode-cn.com/problems/letter-combinations-of-a-phone-number
3334- 字节
3435- 腾讯
3536
36- ## 思路
37+ ## 回溯
38+
39+ ### 思路
3740
3841由于要求所有的可能性,因此考虑使用回溯法进行求解。回溯是一种通过穷举所有可能情况来找到所有解的算法。如果一个候选解最后被发现并不是可行解,回溯算法会舍弃它,并在前面的一些步骤做出一些修改,并重新尝试找到可行解。究其本质,其实就是枚举。
3942
@@ -44,16 +47,17 @@ https://leetcode-cn.com/problems/letter-combinations-of-a-phone-number
4447- 遍历下一个数字所对应的所有映射的字母
4548- 将当前的字母添加到组合最后,也就是 str + tmp[ r]
4649
47- ## 关键点
50+ ### 关键点
4851
4952- 回溯
5053- 回溯模板
5154
52- ## 代码
55+ ### 代码
5356
5457- 语言支持:JS, C++, Java, Python
5558
5659JavaScript Code:
60+
5761``` js
5862/**
5963 * @param {string} digits
@@ -90,8 +94,8 @@ const letterCombinations = function (digits) {
9094};
9195```
9296
93-
9497C++ Code:
98+
9599``` c++
96100class Solution {
97101public:
@@ -126,6 +130,7 @@ public:
126130```
127131
128132Java Code:
133+
129134``` java
130135class Solution {
131136
@@ -172,6 +177,7 @@ class Solution {
172177```
173178
174179Python Code:
180+
175181``` py
176182class Solution (object ):
177183 def letterCombinations (self , digits ):
@@ -186,7 +192,7 @@ class Solution(object):
186192 self .res = []
187193 self .dfs(digits, 0 , " " )
188194 return self .res
189-
195+
190196 def dfs (self , digits , index , s ):
191197 # 递归的终止条件,用index记录每次遍历到字符串的位置
192198 if index == len (digits):
@@ -207,8 +213,80 @@ class Solution(object):
207213
208214N + M 是输入数字的总数
209215
210- - 时间复杂度:O(3^N \* 4^M)
211- - 空间复杂度:O(3^N \* 4^M)
216+ - 时间复杂度:O(2^N),其中 N 为 digits 对于的所有可能的字母的和。
217+ - 空间复杂度:O(2^N),其中 N 为 digits 对于的所有可能的字母的和。
218+
219+ ## 笛卡尔积
220+
221+ ### 思路
222+
223+ 不难发现, 题目要求的是一个笛卡尔积。
224+
225+ 比如 digits = 'ab',其实就是 a 对应的集合 {'a', 'b', 'c'} 和 b 对应的集合 {'d', 'e', 'f'} 笛卡尔积。
226+
227+ 简单回忆一下笛卡尔积的内容。对于两个集合 A 和 B,A×B = {(x,y)|x∈A∧y∈B}。
228+
229+ 例如,A={a,b}, B={0,1,2},则:
230+
231+ - A×B={(a, 0), (a, 1), (a, 2), (b, 0), (b, 1), (b, 2)}
232+ - B×A={(0, a), (0, b), (1, a), (1, b), (2, a), (2, b)}
233+
234+ 实际上,力扣关于笛卡尔积优化的题目并不少。 比如:
235+
236+ - [ 140. 单词拆分 II] ( https://github.com/azl397985856/fe-interview/issues/153 )
237+ - [ 95. 不同的二叉搜索树 II] ( https://github.com/azl397985856/leetcode/blob/master/problems/95.unique-binary-search-trees-ii.md )
238+ - 96.unique-binary-search-trees
239+ - 等等
240+
241+ 知道了这一点之后,就不难写出如下代码。
242+
243+ 由于我们使用了笛卡尔积优化, 因此可以改造成纯函数,进而使用记忆化递归,进一步降低时间复杂度, 这是一个常见的优化技巧。
244+
245+ ### 关键点
246+
247+ - 笛卡尔积
248+ - 记忆化递归
249+
250+ ### 代码
251+
252+ 代码支持:Python3
253+
254+ ``` py
255+
256+ # 输入:"23"
257+ # 输出:["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"].
258+ class Solution :
259+ def letterCombinations (self , digits : str ) -> List[str ]:
260+ mapper = [" " , " " , " abc" , " def" , " ghi" ,
261+ " jkl" , " mno" , " pqrs" , " tuv" , " wxyz" ]
262+ @lru_cache (None )
263+ def backtrack (digits , start ):
264+ if start >= len (digits):
265+ return [' ' ]
266+ ans = []
267+ for i in range (start, len (digits)):
268+ for c in mapper[int (digits[i])]:
269+ # 笛卡尔积
270+ for p in backtrack(digits, i + 1 ):
271+ # 需要过滤诸如 "d", "e", "f" 等长度不符合的数据
272+ if start == 0 :
273+ if len (c + p) == len (digits):
274+ ans.append(c + p)
275+ else :
276+ ans.append(c + p)
277+ return ans
278+ if not digits:
279+ return []
280+ return backtrack(digits, 0 )
281+
282+ ```
283+
284+ ** 复杂度分析**
285+
286+ N + M 是输入数字的总数
287+
288+ - 时间复杂度:O(N^2),其中 N 为 digits 对于的所有可能的字母的和。
289+ - 空间复杂度:O(N^2),其中 N 为 digits 对于的所有可能的字母的和。
212290
213291大家对此有何看法,欢迎给我留言,我有时间都会一一查看回答。更多算法套路可以访问我的 LeetCode 题解仓库:https://github.com/azl397985856/leetcode 。 目前已经 37K star 啦。
214292大家也可以关注我的公众号《力扣加加》带你啃下算法这块硬骨头。
0 commit comments