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位数而不知使用几重循环的问题。

🌈代码实现

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

✏代码注释

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

🌟解法二:笛卡尔积🌟

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

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

import itertools

a = [1, 2, 3]
b = [4, 5]
print("a,b的笛卡尔乘积:"),
for x in itertools.product(a, b):
    print(x)
print("a自身的笛卡尔乘积:"),
for x in itertools.product(a, a):
    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)
(了解更多笛卡尔积大家可以自行搜索)

 🌈代码实现

class Solution(object):
    def letterCombinations(self, digits):
        dct = {          
            "2": "abc",
            "3": "def",
            "4": "ghi",
            "5": "jkl",
            "6": "mno",
            "7": "pqrs",
            "8": "tuv",
            "9": "wxyz",
        }
        if not digits:     
            return list()
        groups = (dct[digit] for digit in digits)  
        return ["".join(item) for item in itertools.product(*groups)]   
        
        #  ["".join(item) for item in itertools.product(*groups)] 
        # ans = []    
        # for item in itertools.product(*groups):    
        #     temp = "".join(item)    
        #     ans.append(temp)        
        # return ans

✏代码注释

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

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

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

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

🌟解法三:回溯🌟

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

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

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

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

🌈代码实现

class Solution:
    def letterCombinations(self, digits):
        dct = {
            "2": "abc",
            "3": "def",
            "4": "ghi",
            "5": "jkl",
            "6": "mno",
            "7": "pqrs",
            "8": "tuv",
            "9": "wxyz",
        }
        if not digits:        
            return list()

        def backtrack(index):    
            if index == len(digits):   
                ans.append("".join(item))    
            else:                       
                digit = digits[index]    
                for letter in dct[digit]:    
                    item.append(letter)     
                    backtrack(index + 1)    
                    item.pop()           

                                        
        item = list()    
        ans = list()     
        backtrack(0)    
        return ans    

✏代码注释

class Solution:
    def letterCombinations(self, digits):
        dct = {
            "2": "abc",
            "3": "def",
            "4": "ghi",
            "5": "jkl",
            "6": "mno",
            "7": "pqrs",
            "8": "tuv",
            "9": "wxyz",
        }
        if not digits:        # digits为空的返回
            return list()

        def backtrack(index):    # index为下标或索引

            if index == len(digits):   # 下标到达digits的长度说明以获取到一个完整字母组合

                ans.append("".join(item))    # 将该字母组合添加到结果列表

            else:                        # 如果没获取到一个完整字母组合则继续

                digit = digits[index]     # 取下一个数字

                for letter in dct[digit]:    # 遍历当前数字所对应的字母

                    item.append(letter)     # 将该字母添加到item中(后)形如['a', 'd']

                    backtrack(index + 1)    # 下标+1进入下一层递归

                    item.pop()           # 回溯,删除当前组合最后一个字母,回到前一步,如从['a', 'd']删除'd',回到['a']

                                        # 再进行 ['a', 'f']的组合

        item = list()    # 用于放置单个的字母组合列表
        ans = list()     # 放置所有组合列表
        backtrack(0)    # 调用backtrack(0)开始回溯
        return ans     # 返回结果

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

  • 9
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论
问题:给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。给出数字到字母的映射和一个数字字符串,按按键顺序给出所有可能的字母组合。 根据题目要求,我们可以使用回溯算法来解决该问题。 具体算法步骤如下: 1. 定义一个映射表,将数字与字母的映射关系存储起来。 2. 定义一个结果列表,用于存储所有可能的字母组合。 3. 定义一个递归函数 backtracking,用于生成所有可能的字母组合。 - 递归函数参数包括当前生成的字母组合 combination、剩余待处理的数字字符串 digits 和当前处理的层数 level。 - 如果当前处理的层数等于数字字符串的长度,将当前生成的字母组合添加到结果列表中,并返回。 - 否则,获取当前层对应的数字,并依次取出映射的字母。 - 对于每个字母,将字母加入到当前生成的字母组合中,并递归调用 backtracking 函数处理下一层。 - 处理完毕后,将当前加入的字母移除,进行下一轮循环。 4. 调用递归函数 backtracking,传入初始的字母组合为空串,剩余待处理的数字字符串为给定数字字符串,层数初始值为 0。 5. 返回结果列表算法实现如下: ```python def letterCombinations(digits): if digits == "": return [] mapping = { '2': 'abc', '3': 'def', '4': 'ghi', '5': 'jkl', '6': 'mno', '7': 'pqrs', '8': 'tuv', '9': 'wxyz' } result = [] def backtracking(combination, digits, level): if level == len(digits): result.append(combination) return letters = mapping[digits[level]] for letter in letters: backtracking(combination + letter, digits, level + 1) backtracking("", digits, 0) return result ``` 测试样例: ```python print(letterCombinations("23")) # ["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"] print(letterCombinations("")) # [] print(letterCombinations("2")) # ["a", "b", "c"] ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

亖夕

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值