LeetCode偶尔一题 —— 39. Combination Sum(回溯算法系列)

题目描述

Given a set of candidate numbers (candidates) (without duplicates) and a target number (target), find all unique combinations in candidates where the candidate numbers sums to target. javascript

The same repeated number may be chosen from candidates unlimited number of times. 前端

Note:java

  • All numbers (including target) will be positive integers.
  • The solution set must not contain duplicate combinations.

大意:给定一组不含重复数字的数组和一个目标数字,在数组中找出全部数加起来等于给定的目标数字的组合。git

输入

candidates = [2,3,6,7], target = 7

输出

[
  [7],
  [2,2,3]
]

分析题目

因为咱们须要找到多个组合,简单的使用 for 循环确定是不行的,这时候咱们能够使用回溯算法来解决这个问题。github

用回溯算法解决问题的通常步骤:算法

  1. 针对所给问题,定义问题的解空间,它至少包含问题的一个(最优)解。
  2. 肯定易于搜索的解空间结构,使得能用回溯法方便地搜索整个解空间 。
  3. 以深度优先的方式搜索解空间,而且在搜索过程当中用剪枝函数避免无效搜索。

根据题目的描述咱们知道它知足了咱们所说的步骤一,下面咱们来肯定搜索的思路👇数组

搜索的思路

回溯通常须要遍历全部的状况来找出问题的解,在写代码以前咱们不妨先画出一个递归树,理清咱们写代码的思路👇微信

因为数组中的数字是能够被重复使用的,因此对于同一个数字也要向下递归。可是,对于 [2,2,3][2,3,2] 这样的结果 实际上是重复的,咱们须要剔除掉重复的项。
能够这样优化递归树👇函数

其余问题

如何保存数据

刚刷题目的时候看到这类多种解的问题常常会感到懵逼,其实这里一般的解法是传入一个临时数组,进入递归前 push 一个结果,结束以前能够用一个全局数组保存下来,结束以后在临时数组pop 掉它。优化

如何肯定结束条件

结束条件一般题目中就会给出,通常来讲找到给出的解或者递归层数达到上限就能够结束递归

示例代码

function foo (nums, target) {
    let result = []
    
    dfs(0, 0, [])
    return result
    
    function dfs (index, sum, tmp) {
        if (sum === target) {
            result.push(tmp.slice())
        }
        if (sum > target) {
            return
        }
        for (let i = index; i < nums.length; i++) {
            tmp.push(nums[i])
            dfs(i, sum + nums[i], tmp)
            tmp.pop()
        }
    }
}

总结

对于这类题目,使用回溯算法显然很方便。固然,除了递归以外也能用 或者 队列 来解决。另外,对于前端同窗,遇到须要开辟临时数组的题目时,若是存在赋值操做,记得返回它的浅复制,如 result.push(tmp.slice()),不然会对结果产生影响。

原题地址: Combination Sum
代码不定时更新,欢迎 star 个人 repo

扫描下方的二维码或搜索「tony老师的前端补习班」关注个人微信公众号,那么就能够第一时间收到个人最新文章。

相关文章
相关标签/搜索