dfs+剪枝,LeetCode 39. 组合总和

一、题目

1、题目描述

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

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

对于给定的输入,保证和为 target 的不同组合数少于 150 个。

2、接口描述

python3
复制代码
​
python 复制代码
class Solution:
    def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
cpp
复制代码
​
cpp 复制代码
class Solution {
public:
    vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
        
    }
};

3、原题链接

39. 组合总和


二、解题报告

1、思路分析

考虑暴力dfs,选多个或不选,当前枚举到 i ,还差res数值

复制代码
            dfs(i - 1, res)

            path.append(candidates[i])
            dfs(i, res - candidates[i])
            path.pop()

显然可以剪枝,res 小于0的时候剪掉(可行性剪枝)

进一步,我们优化搜索顺序,从小到大枚举

当res < candidatei时,往后枚举不能满足,也可以剪枝(优化搜索顺序剪枝)

这样这道题其实就蛮快了

但是如果数据量更大呢?

搜索树的起点终点已知,可以双向广搜,能够有效降低复杂度

但是我们发现每个结点都相当于一个完全背包的状态

换言之,我们预处理完全背包,就可以使得搜索顺序朝着可行路径去走

所以采用预排序和预处理完全背包来进行剪枝:

优化搜索顺序 & 可行性剪枝

2、复杂度

时间复杂度: 不会算 空间复杂度:O(n target)

3、代码详解

python3
复制代码
​
python 复制代码
class Solution:
    def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
        n = len(candidates)
        candidates.sort()
        f = [[False] * (target + 1) for _ in range(n + 1)]
        f[0][0] = True
        for i, x in enumerate(candidates):
            for j in range(target + 1):
                f[i + 1][j] = f[i][j] or j >= x and f[i + 1][j - x]
        
        ret = []
        path = []
        def dfs(i: int, res: int):
            if not res:
                ret.append(path.copy())
                return
            
            if res < 0 or not f[i + 1][res]:
                return
            
            dfs(i - 1, res)

            path.append(candidates[i])
            dfs(i, res - candidates[i])
            path.pop()

        dfs(n - 1, target)

        return ret
        
cpp
复制代码
​
cpp 复制代码
class Solution {
public:
    vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
        vector<vector<int>> ret;
        vector<int> path;
        int n = candidates.size();
        sort(candidates.begin(), candidates.end());
        vector<vector<bool>> f(n + 1, vector<bool>(target + 1));
        f[0][0] = 1;
        for(int i = 0; i < n; i++)
            for(int j = 0; j <= target; j++)
                f[i + 1][j] = f[i][j] || (j >= candidates[i] && f[i + 1][j - candidates[i]]);
        function<void(int, int)> dfs = [&](int i, int res){
            if(!res) {
                ret.emplace_back(path);
                return;
            }
            if(res < 0 || !f[i + 1][res]) return;
            dfs(i - 1, res);

            path.emplace_back(candidates[i]);
            dfs(i, res - candidates[i]);
            path.pop_back();
        };
        dfs(n - 1, target);
        return ret;
    }
};
相关推荐
yi0114 小时前
LeetCode 219:存在重复元素 II——哈希表记录“最近一次出现的位置”
数据结构·人工智能·笔记·python·算法·leetcode·哈希表
灯澜忆梦7 小时前
【面向对象编程C++】| 基础语法
java·c++·算法
小蒋观天下7 小时前
专项方案:大场景港口AI安防、多干扰环境下的算法调优与落地实操
人工智能·深度学习·算法·安全·机器学习·计算机视觉·ai大模型
Evand J7 小时前
【电机滤波例程5】渐消因子自适应扩展卡尔曼滤波(EKF),MATLAB。PMSM负载突变下的状态估计。附下载链接
算法·matlab
H.莓飛7 小时前
【数据结构】二叉树_OJ题
linux·开发语言·数据结构·算法
好想像大佬一样能够ak所有8 小时前
Leetcode35.搜索插入位置
数据结构·算法·leetcode
aqiu1111118 小时前
【C++算法打怪专栏】LeetCode 165. 比较版本号(双指针与字符串流法)
c++·算法·leetcode
黄金龙PLUS8 小时前
如何基于置换算法来设计对称加密算法
算法·网络安全·密码学·哈希算法·同态加密
不会就选b8 小时前
算法日常・每日刷题--<动态规划>14
算法
赛博守夜人9 小时前
跨境业务与出海合规之九:海外买量投放与营销虚假流量(Ad Fraud):跨国机房群控与归因欺诈识别算法
算法·安全