Day25算法学习|回溯算法 组合

题目 216.组合总和III

问题描述

找出所有相加之和为n的k个数的组合。组合中只允许含有1-9的正整数,并且每种组合中不存在重复的数字
说明:

所有数字都是正整数。
解集不能包含重复的组合。
在这里插入图片描述

解题思路

在这里插入图片描述
本题是从1到9里面选k个数,然后和为n。
所以本题涉及到两个减枝操作:

  • 像上道题一样要凑够k个数,本题的n就是9了
  • 当前和大于目标和减,在回溯之前能操作

代码


class Solution:
    def combinationSum3(self, k: int, n: int) -> List[List[int]]:
        result = []  # 存放结果集
        self.backtracking(n, k, 0, 1, [], result)
        return result

    def backtracking(self, targetSum, k, currentSum, startIndex, path, result):
        if currentSum > targetSum:  # 剪枝操作
            return  # 如果当前和已经超过目标和,直接返回
        if len(path) == k:
            if currentSum == targetSum:
                result.append(path[:])
            return
        for i in range(startIndex, 10):  # 从startIndex到9遍历数字
            currentSum += i  # 选择数字
            path.append(i)  # 添加到组合中
            self.backtracking(targetSum, k, currentSum, i + 1, path, result)  # 递归调用,更新currentSum和startIndex
            currentSum -= i  # 回溯
            path.pop()  # 回溯中移除数字

复杂度分析

  • 时间复杂度O(k * C(9, k))

    在9个数字中选择k个,因此有C(9, k)种可能的组合。对于每个组合,我们需要复制一份加入到结果中,所以总的时间复杂度是O(k * C(9, k))。

  • O(k + C(9, k))

输出结果的存储空间:与上述类似,输出结果的存储空间为O(C(9, k)),因为这是从9个元素中选择k个元素的组合数。

递归栈的空间:递归的深度最多是k,所以递归栈需要的空间是O(k)。

其他空间:包括path和一些变量i的空间,但是这些都可以忽略不计,因为它们的大小是固定的。

题目 17.电话号码的字母组合

重做的代码问题

self.s的初始值应该是"“,而不是” "。

在递归函数backtracking中,每次调用时,你需要递增索引值index,以便处理数字字符串中的下一个数字。

在Python中,要删除字符串的最后一个字符,可以使用self.s = self.s[:-1]。
for i in “abc”: i=a/b/c

问题描述

给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。

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

示例:

输入:“23”
输出:[“ad”, “ae”, “af”, “bd”, “be”, “bf”, “cd”, “ce”, “cf”].
在这里插入图片描述

解题思路

  • 本题其实就是一个排列组合,按下“23”两个键,就会出现9种情况的字母组合。

  • 这个问题可以化成二叉树吗,比如:

  • 在这里插入图片描述

  • 把每个数字代表的字母组合想象成一个长度为3或者4的string,可以按顺序创建一个列表或者字典,为了代码更加精简采用列表。

  • 定义代码结构

    • 首先定义一个init函数,把字母列表,可能的组合s,结果result,作为全局变量定义好。
    • 定义backTracking回溯函数,进行回溯操作,需要输入的digits和index作为函数,index是digits函数的索引,就是索引当前digits对应的digit。
    • backTracking中,终止条件:就是len(digits)==index的时候,result记录s,可能会觉得index索引怎么可能和长度相同,s每添加一个字母,index都要加1,当加完的时候,index=2,此时再一次调用回溯函数,已经停止了。
    • backTracking中,回溯逻辑:先把digits中对应的digit转化为int形,获取对应的字母集,然后进行第一个for循环,s添加第一个字母,index加一,再对下一个digit对应的字母集进行递归。然后进行回溯操作,返回到第二个循环。

代码


class Solution:
    def __init__(self):
        self.case={

            0:"",
            1:"",
            2:"abc",
            3:"def",
            4:"ghi",
            5:"jkl",
            6:"mno",
            7:"pqrs",
            8:"tuv",
            9:"wxyz"
        }
        self.s=""
        self.res=[]
    
    def backtracking(self, digits, index):
        #index is the len of the s, s must euqls to the digita as result
        #end
        if len(digits)==index:
            self.res.append(self.s)
            return
        #single layer
        #因为数字不同,所以每次循环的长度不同,设置一个index保存当前记录的数字下标

        for j in self.case[int(digits[index])]:
            self.s+=j
            self.backtracking(digits,index+1)
            #易错点
            self.s=self.s[:-1]
        #backtracking
    def letterCombinations(self, digits):
        if digits=="":
            return []
        self.backtracking(digits,0)
        return self.res

复杂度分析

  • 时间复杂度O(4^n)

    n为输入字符串digits的长度。这是因为在最坏情况下,每个数字都会对应到4个字母(比如7和9对应’pqrs’和’wxyz’

  • 空间复杂度 O(n)

  • 使用了递归,并且递归的深度等于digits的长度。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值