LeetCode之回溯1——电话号码的字母组合(17)、括号生成(22)、复原IP地址(93)

1、电话号码的字母组合(17)

题目描述:

【中等】

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

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

在这里插入图片描述
示例一:

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

题目链接

思路分析

1、对与“23”我们不难推断出它的解为下图:

在这里插入图片描述

  • 这显然是在树形结构求树叶的全部解,在树形结构中找全部的解,通常使用回溯算法。

2、先写出数字与字符一一映射的字典,phone={‘数字(key)’:‘对应字母(value)’}。

3、在这道题中,由于每个数字对应的每个字母都可能进入字母组合,因此不存在不可行的解,直接穷举所有的解即可。

定义回溯函数:

  • 回溯出口:如果回溯次数与数字字符串长度一致,就是一个可行解,将其存储在结果表中。
  • 回溯主体:对于每一个数字字符串中的数字所对应的字母做以下操作:
    • 将其添加到一个可行解列表中
    • 对于下一个字符进行回溯操作
    • 取消标记,状态返回即恢复可行解列表为空
class Solution:
    def letterCombinations(self, digits: str) -> List[str]:
        if not digits:
            return []
        #定义数字字符映射字典
        phonemap={
    
    
            "2": "abc",
            "3": "def",
            "4": "ghi",
            "5": "jkl",
            "6": "mno",
            "7": "pqrs",
            "8": "tuv",
            "9": "wxyz",
        }
        #存储可行解
        combination=[]
        #存储最终解,集合可行解
        combinations=[]
        #定义回溯函数
        def backtrack(i):
            #回溯出口:满足条件的解
            #如果回溯次数等于数字字符串的长度,就是一个可行解
            if i==len(digits):
                combinations.append("".join(combination))
            #回溯主体
            else:
                digit=digits[i]
                for letter in phonemap[digit]:
                    combination.append(letter)
                    #对数字字符串的下一个数字进行回溯
                    backtrack(i+1)
                    #取消标记,状态返回,不再走这条路
                    combination.pop()#combination再次为空
        backtrack(0)
        return combinations
  • 时间复杂度: O ( 3 m + 4 n ) O(3^m+4^n) O(3m+4n),其中m是输入中对应3个字母的数字个数,n是输入中对应4个字母的数字个数。
  • 空间复杂度: O ( m + n ) O(m+n) O(m+n)

2、括号生成(22)

题目描述:

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

示例1:

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

题目链接

思路分析

3、复原IP地址(93)

题目描述:

【中等】

给定一个只包含数字的字符串,复原它并返回所有可能的 IP 地址格式。

有效的 IP 地址 正好由四个整数(每个整数位于 0 到 255 之间组成,且不能含有前导 0),整数之间用 ‘.’ 分隔。

例如:“0.1.2.201” 和 “192.168.1.1” 是 有效的 IP 地址,但是 “0.011.255.245”、“192.168.1.312” 和 “[email protected]” 是 无效的 IP 地址。

示例一:

输入:s = "25525511135"
输出:["255.255.11.135","255.255.111.35"]

题目链接

思路分析

1、有效的 IP 地址 正好由四个整数(每个整数位于 0 到 255 之间组成,且不能含有前导 0),因此我们可以首先以1,2,3个字符进行第一次分割然后查看后面的是否能够满足,一旦发现不满,就将这一路封死。如下图:
在这里插入图片描述
2、需要进行剪枝情况:

1、一开始,字符串的长度小于 4 或者大于 12 ,一定不能拼凑出合法的 ip 地址(这一点可以一般化到中间结点的判断中,以产生剪枝行为);

2、每一个结点可以选择截取的方法只有 3 种:截 1 位、截 2 位、截 3 位,因此每一个结点可以生长出的分支最多只有 3 条分支;

根据截取出来的字符串判断是否是合理的 ip 段,这里写法比较多,可以先截取,再转换成 int ,再判断。我采用的做法是先转成 int,是合法的 ip 段数值以后,再截取。

3、由于 ip 段最多就 4 个段,因此这棵三叉树最多 4 层,这个条件作为递归终止条件之一;

4、每一个结点表示了求解这个问题的不同阶段,需要的状态变量有:

class Solution:
    def restoreIpAddresses(self, s: str) -> List[str]:
        
        result = []
        def addOnePoint(src, dst, cnt):
            if not src and cnt == 4:
                result.append(dst[:-1])
            if src and cnt < 4:
                for i in range(1, 4):
                    if len(src) >= i and 0 <= int(src[:i]) <= 255 and str(int(src[:i])) == src[:i]:
                        addOnePoint(src[i:], dst + src[:i] + '.', cnt + 1)
        addOnePoint(s, '', 0)
        return result



猜你喜欢

转载自blog.csdn.net/weixin_45666566/article/details/113800589