代码随想录算法训练营day25|leetcode 216|17

leetcode216组合总和III

216. 组合总和 III - 力扣(Leetcode)

找出所有相加之和为 n 的 k 个数的组合,且满足下列条件:

  • 只使用数字1到9
  • 每个数字 最多使用一次 

返回 所有可能的有效组合的列表 。该列表不能包含相同的组合两次,组合可以以任何顺序返回。

思路:和之前做过的组合I大概思路是一样的,但是这道题多了一个 计算集合内的总和。

n代表我们k个数字的和,也就是k个数字相加==n

依然转化树形结构来看,k相当于树的深度,9相当于树的宽度,题目中说了只能是1-9的数字

选取过程如上图所示(来自代码随想录)

依然是递归三部曲:

        终止条件:如果当前path长度达到k,然后path内元素的和==n,那么就加入结果集 并且return

        递归参数:n,k,sum(调用的时候默认从0开始),startindex(下一层递归的位置)

        单层循环逻辑:也就是一个循环遍历1-9的数字,然偶sum+=i.别忘了之前说过了。递归和回溯是一起的,有加就要有减,才可以回到上一层继续遍历其他的路。

然后开始递归

代码:

def combinationSum3(self, k: int, n: int) -> List[List[int]]:
        res = []
        path = []
        def traceback(k,n,sum,startindex):
            if len(path)==k:
                if sum==n:
                    res.append(path[:])
                    return 
            for i in range(startindex,10):
                path.append(i)
                sum+=i
                traceback(k,n,sum,i+1)
                sum-=i
                #回溯 有加就要减掉
                path.pop()
        traceback(k,n,0,1)
        return res 


"""递归三部曲:
    终止条件:题目给出了k,n那么我们这个树的大小也就确定了。k就代表是树的深度。
    n就是树的宽度。所以找到了k个数之后如果再往后找也就没有了其他多余的意义了。
    
    传入参数:k,n,sum,startindex sum就是每个集合中元素的总和。
    判断是不是等于N时候才会加入最后
    的结果集。sum最后调用默认是从0开始的 startindex代表下一次递归是从哪里开始的
    
    单程循环逻辑:既然确定是1-9中,那么sum每次就会+=i然后记录 是否等于n,在选择加不加入结果集
    那么如果当前这个符合或者不符合,我们都需要回到上一层遍历其他的节点,
    所以回溯在处理的时候如果有+
    那么在递归之后就需要减。加了多少就要减多少 才回到上一层。
    最后pop掉"""

Leetcode17电话号码的字母组合

17. 电话号码的字母组合 - 力扣(Leetcode)

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

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

 

最最最最暴力的方法,for循环嵌套。或者直接用python的内置函数iteral.product求笛卡尔乘积,学过sql的朋友应该不陌生,这道题就是类似sql的join然后求笛卡尔乘积

但是我们开始了回溯算法的章节,那么肯定要用回溯来写!

思路:首先需要创一个哈希表,数字和他所映射的字母 一 一 对应

        然后依旧是转化为树形结构来看,如下图!

        

树的深度就是当前digits的长度,而最后的叶子节点就是我们要收集的结果,那么回溯出现在哪里呢?是不是最后一层找完了我们要继续回到上一层去找。

 递归三部曲:

        终止条件:如果index==len(digits),index就代表当前遍历的位置,如果index等于了当前digits的长度,那么就加入结果集并return

        递归参数:首先需要一个字符串s来收集叶子节点的结果,然后用一个字符串数组result保存。也就是:s,digits,index

        单层循环逻辑:首先找到当前要遍历digits中字母的位置,也就是map[digits[index]],index从0开始,获取到了第一个数字 然后再map中找到了这个数字映射的字母

  for循环对这个数字指向的字母,s+=i,因为s是字符串哈!我们最后传入的时候是一个" ".

然后开始递归下一层,这里递归了之后是需要返回到上一层的,也就是s = s[:-1],这个就代表我们回溯到上一层的字母。然后继续遍历其他的字母。

这里递归我讲一下,主要是熟悉这个思路,至于递归里面的过程真的没有必要去扣出来,因为一不小心就会绕进去然后出不来,虽然我每次都被绕进去。。。。。

代码:

 def letterCombinations(self, digits: str) -> List[str]:
        result = []
        def backtrace(digits,index,s:str):
            map ={  '2':'abc',
                    '3':'def',
                    '4':'ghi',
                    '5':'jkl',
                    '6':'mno',
                    '7':'pqrs',
                    '8':'tuv',
                    '9':'wxyz'}
            if not digits:
                return []
            if index==len(digits):
                result.append(s)
                return 
            letters = map[digits[index]]
            for letter in letters:
                s+=letter 
                backtrace(digits,index+1,s)
                s=s[:-1]
        backtrace(digits,0,'')
        return result 

        

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值