• python每日一练-----电话号码的字母组合


    🌥(day57:P51)

    好久没写题解文章了,今天重操旧业。

    目录

    📝题目:

    🚩题目分析:

    💡解题思路:

    🌟解法一:列表解析式🌟

    🌈代码实现

    ✏代码注释

    🌟解法二:笛卡尔积🌟

     🌈代码实现

    ✏代码注释

    🌟解法二:回溯🌟

    🌈代码实现


    📝题目:

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

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

    • 0 <= digits.length <= 4
    • digits[i] 是范围 ['2', '9'] 的一个数字。 

    电话上数字所对应的字母

    ⭐示例 1:

    输入:digits = "23"

    输出:["ad","ae","af","bd","be","bf","cd","ce","cf"]

    ⭐示例 2:

    输入:digits = ""

    输出:[]

     ⭐示例 3:

    输入:digits = "2"

    输出:["a","b","c"]

    🚩题目分析:

    题目看起来就是简单的排列组合,暴力解题未尝不可,但是直接使用for循环解题还是过于粗暴,比如当digits是二位数可以使用两重for循环,digits为三位数可以使用三重for循环,但是我们不知道输入的是digits几位数(当然你可以使用if语句判断digits是几位数就进行几重循环)。下面我们减少粗暴,更“优雅”解题。

    💡解题思路:

    🌟解法一:列表解析式🌟

    我们还是运用排列组合的思想,首先先取出第一个数字中所有对应的字符

    如2对应的字母:

    a,b,b

    接着再取下一个数字

    如设下一数字为3,则3对应的字母:

    d,e,f

    那么我们将其全排列有:

    ['ad', 'ae', 'af', 'bd', 'be', 'bf', 'cd', 'ce', 'cf']

    接着我们又取下一个数字

    如设下一数字为4,则4对应的字母:

    g,h,i

    然后我们将g,h,i和上一次全排列获取到的结果进行排列组合

    得:['adg', 'adh', 'adi', 'aeg', 'aeh', 'aei', 'afg', 'afh', 'afi', 'bdg', 'bdh', 'bdi', 'beg', 'beh', 'bei', 'bfg', 'bfh', 'bfi', 'cdg', 'cdh', 'cdi', 'ceg', 'ceh', 'cei', 'cfg', 'cfh', 'cfi']

    细心的朋友可能已经发现了,这里的排列组合其实就相当于两重for循环。将下一个数字的对应的字母和上一次全排列的结果做全排列,我们就可以解决上述题目分析中未知digits位数而不知使用几重循环的问题。

    🌈代码实现

    1. class Solution(object):
    2. def letterCombinations(self, digits):
    3. dct = {'2': ['a', 'b', 'c'],
    4. '3': ['d', 'e', 'f'],
    5. '4': ['g', 'h', 'i'],
    6. '5': ['j', 'k', 'l'],
    7. '6': ['m', 'n', 'o'],
    8. '7': ['p', 'q', 'r', 's'],
    9. '8': ['t', 'u', 'v'],
    10. '9': ['w', 'x', 'y', 'z']}
    11. if digits == '':
    12. return []
    13. ans = ['']
    14. for num in digits:
    15. ans = [item+ap for item in ans for ap in dct[num]]
    16. return ans

    ✏代码注释

    1. class Solution(object):
    2. def letterCombinations(self, digits):
    3. dct = {'2': ['a', 'b', 'c'], # 用于映射数字和字母关系的字典
    4. '3': ['d', 'e', 'f'],
    5. '4': ['g', 'h', 'i'],
    6. '5': ['j', 'k', 'l'],
    7. '6': ['m', 'n', 'o'],
    8. '7': ['p', 'q', 'r', 's'],
    9. '8': ['t', 'u', 'v'],
    10. '9': ['w', 'x', 'y', 'z']}
    11. if digits == '': # digits为空,返回空列表
    12. return []
    13. ans = [''] # 初始化元素为字符型的列表
    14. for num in digits: # 遍历输入的数字字符串
    15. # 从ans取出item,ans为上一次排列组合的所有结果,item则为其中的一种结果
    16. # 从dct[num]取出ap,dct[num]为当前数字对应的字母列表,ap则为其中的一个字母
    17. # 列表解析式将其排列组合(等效于双重for循环)
    18. ans = [item+ap for item in ans for ap in dct[num]]
    19. return ans

    🌟解法二:笛卡尔积🌟

    笛卡尔积和排列组合的思路差不多,我们使用itertools库来实现笛卡尔积

    我们直观先体验笛卡尔积的使用

    1. import itertools
    2. a = [1, 2, 3]
    3. b = [4, 5]
    4. print("a,b的笛卡尔乘积:"),
    5. for x in itertools.product(a, b):
    6. print(x)
    7. print("a自身的笛卡尔乘积:"),
    8. for x in itertools.product(a, a):
    9. print(x)

    输出

    a,b的笛卡尔乘积:
    (1, 4)
    (1, 5)
    (2, 4)
    (2, 5)
    (3, 4)
    (3, 5)
    a自身的笛卡尔乘积:
    (1, 1)
    (1, 2)
    (1, 3)
    (2, 1)
    (2, 2)
    (2, 3)
    (3, 1)
    (3, 2)
    (3, 3)
    (了解更多笛卡尔积大家可以自行搜索)

     🌈代码实现

    1. class Solution(object):
    2. def letterCombinations(self, digits):
    3. dct = {
    4. "2": "abc",
    5. "3": "def",
    6. "4": "ghi",
    7. "5": "jkl",
    8. "6": "mno",
    9. "7": "pqrs",
    10. "8": "tuv",
    11. "9": "wxyz",
    12. }
    13. if not digits:
    14. return list()
    15. groups = (dct[digit] for digit in digits)
    16. return ["".join(item) for item in itertools.product(*groups)]
    17. # ["".join(item) for item in itertools.product(*groups)]
    18. # ans = []
    19. # for item in itertools.product(*groups):
    20. # temp = "".join(item)
    21. # ans.append(temp)
    22. # return ans

    ✏代码注释

    1. class Solution(object):
    2. def letterCombinations(self, digits):
    3. dct = { # 数字和字母映射字典,和上面不同的是,字母不使用列表单个储存
    4. "2": "abc",
    5. "3": "def",
    6. "4": "ghi",
    7. "5": "jkl",
    8. "6": "mno",
    9. "7": "pqrs",
    10. "8": "tuv",
    11. "9": "wxyz",
    12. }
    13. if not digits: # 判断是否为空
    14. return list()
    15. groups = (dct[digit] for digit in digits) # 生成字母组合对象,如list(groups) =['abc', 'def', 'ghi']
    16. return ["".join(item) for item in itertools.product(*groups)] # 进行组合并返回结果
    17. # ["".join(item) for item in itertools.product(*groups)] 列表解析式等价于
    18. # ans = [] # 结果列表
    19. # for item in itertools.product(*groups): # item为('a', 'd', 'g')类型元组
    20. # temp = "".join(item) # 将元组中的元素提取出来拼接成字符串
    21. # ans.append(temp) # 将拼接好的组合字符串添加到结果列表
    22. # return ans

    这里简要介绍itertools.product(*groups)

    *是python中一个赋值的技巧,叫做解包。相信很多人都见过def func(*args, **kwargs)这种写法,在函数中,*代表不定个数的参数,以tuple的方式传入。

    product(*groups)接收若干个位置参数,转换成元组tuple形式

    🌟解法三:回溯🌟

    回溯算法用于寻找所有的可行解,如果发现一个解不可行,则会舍弃不可行的解。在这道题中,由于每个数字对应的每个字母都可能进入字母组合,因此不存在不可行的解,可以直接穷举所有的解即可。

    回溯主要体现再1和2,从2回溯到1

    如当a和d组合后得到一个结果,到达2d位置

    接着我们回溯到1a位置,a再和组合得到另一个结果

    🌈代码实现

    1. class Solution:
    2. def letterCombinations(self, digits):
    3. dct = {
    4. "2": "abc",
    5. "3": "def",
    6. "4": "ghi",
    7. "5": "jkl",
    8. "6": "mno",
    9. "7": "pqrs",
    10. "8": "tuv",
    11. "9": "wxyz",
    12. }
    13. if not digits:
    14. return list()
    15. def backtrack(index):
    16. if index == len(digits):
    17. ans.append("".join(item))
    18. else:
    19. digit = digits[index]
    20. for letter in dct[digit]:
    21. item.append(letter)
    22. backtrack(index + 1)
    23. item.pop()
    24. item = list()
    25. ans = list()
    26. backtrack(0)
    27. return ans

    ✏代码注释

    1. class Solution:
    2. def letterCombinations(self, digits):
    3. dct = {
    4. "2": "abc",
    5. "3": "def",
    6. "4": "ghi",
    7. "5": "jkl",
    8. "6": "mno",
    9. "7": "pqrs",
    10. "8": "tuv",
    11. "9": "wxyz",
    12. }
    13. if not digits: # digits为空的返回
    14. return list()
    15. def backtrack(index): # index为下标或索引
    16. if index == len(digits): # 下标到达digits的长度说明以获取到一个完整字母组合
    17. ans.append("".join(item)) # 将该字母组合添加到结果列表
    18. else: # 如果没获取到一个完整字母组合则继续
    19. digit = digits[index] # 取下一个数字
    20. for letter in dct[digit]: # 遍历当前数字所对应的字母
    21. item.append(letter) # 将该字母添加到item中(后)形如['a', 'd']
    22. backtrack(index + 1) # 下标+1进入下一层递归
    23. item.pop() # 回溯,删除当前组合最后一个字母,回到前一步,如从['a', 'd']删除'd',回到['a']
    24. # 再进行 ['a', 'f']的组合
    25. item = list() # 用于放置单个的字母组合列表
    26. ans = list() # 放置所有组合列表
    27. backtrack(0) # 调用backtrack(0)开始回溯
    28. return ans # 返回结果

    好了到本章到此结束,下期见

  • 相关阅读:
    推文项目进展如何
    Centos搭建socks5代理服务器
    万字总结:CSS伪元素和伪类全网最全解析
    前端工程化:使用 shelljs 生成 yapi 接口文件
    基于Java+SpringBoot+Thymeleaf+Mysql在线电影院选座订票系统设计与实现
    WPF之Window无边框拖动、特殊形状、Grid拖拽
    odoo13笔记点
    Java中Date与LocalDate、LocalDateTime之间的区别及相互转换
    spring cloud负载均衡算法,类型
    如何在.NET Core3.1 类库项目中使用System.Windows.Forms
  • 原文地址:https://blog.csdn.net/m0_61791601/article/details/126556010