回溯算法题目分析(1)

组合问题

77.组合

在写题目前,我们先回顾一下我们的回溯算法的答题模板。

res = []
def backtrack(未探索区域, res, path):
    if  满足条件:
        res.append(path) 
        # return  # 如果不用继续搜索需要 return
    for 选择 in 未探索区域当前可能的选择:
        if 当前选择符合要求:
            backtrack(未探索区域, res, path+已探索的区域)

题目链接:77. 组合 - 力扣(LeetCode) (leetcode-cn.com)

       给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合。你可以按 任何顺序 返回答案。

输入:n = 4, k = 2
输出:
[
  [2,4],
  [3,4],
  [2,3],
  [1,2],
  [1,3],
  [1,4],
]

      这题算是一道很经典的回溯算法的题目,很多一看这道题就会想到用for语句暴力循环,但是随着n和k的增大,算法就很容易超时,不太理想,所以我们可以想到用回溯法来解决问题。

     我们上篇说到,回溯法可以把问题抽象弄成树形结构,更好地理解:

我们把每次的数字保存在path里,当path的数组大小达到了k,就是找到一组结果集合。

回溯法有三部曲:

  • 递归函数的返回值以及参数
  • 回溯函数终止条件
  • 单层搜索的过程

组合问题Python3完整代码如下:

class Solution:
    def combine(self, n: int, k: int) -> List[List[int]]:
        nums = [i for i in range(1,n+1)]//创建从1到n的数组
        ans = []//存放最后答案的数组
 
        def backtrack(nums,path):
            if len(path) == k:// 当满足k长度的我们存进数组
                ans.append(path)
                return
            for i in range(len(nums)):
                backtrack(nums[i+1:],path + [nums[i]])//递归
 
        backtrack(nums,[])
        return ans

​

对比一下本题的代码,是不是跟我们模板很像,所以有了这个模板,就有了解题的大体方向。


77.组合

题目链接:39. 组合总和 - 力扣(LeetCode) (leetcode-cn.com)

给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target ,找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 ,并以列表形式返回。你可以按 任意顺序 返回这些组合。

candidates 中的 同一个 数字可以 无限制重复被选取 。如果至少一个数字的被选数量不同,则两种组合是不同的。 

示例1:

输入:candidates = [2,3,6,7],target = 7
输出:[[2,2,3],[7]]

示例2:

输入: candidates = [2,3,5],target = 8
输出: [[2,2,2,2],[2,3,3],[3,5]]

本题搜索的过程抽象成树形结构如下:

 本题特别的是他没有数组数量的要求,即递归是没有层数限制,只要选取的元素综合超过target就返回。

这题我们需要剪枝优化,当sum>target时候,就可以结束本轮for循环的遍历。

整体代码如下:

class Solution:
    def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
        candidates.sort()//先对无序数组进行排序
        ans = []
        n = len(candidates)

        def backtrack(candidates,target,res):
            if target == 0:
                ans.append(res)
            if target < 0://数组和已经超target就没必要递归
                return 
            for i,c in enumerate(candidates):
                backtrack(candidates[i:],target-c,res+[c])

        backtrack(candidates,target,[])
        return ans

总结:

两道题都是组合的题目,但是每道题的限制条件不一样,元素重不重复决定下次递归的时候数组的起始位置不同,相同的都是其答题模板都相似。

在求和问题中,排序之后加剪枝是常见的套路。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值