dufaxing To be a better man

回溯算法+剪枝

2020-03-28


KYHHbj.png

博客地址

题目描述

给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。
candidates 中的数字可以无限制重复被选取。
说明:
所有数字(包括 target)都是正整数。
解集不能包含重复的组合。

示例 1:

输入: candidates = [2,3,6,7], target = 7,
所求解集为:
[
  [7],
  [2,2,3]
]
输入: candidates = [2,3,5], target = 8,
所求解集为:
[
  [2,2,2,2],
  [2,3,3],
  [3,5]
]

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/combination-sum


思路

根据示例 1:输入: candidates = [2,3,6,7],target = 7。

  • 候选数组里有 2 ,如果找到了 7 - 2 = 5 的所有组合,再在之前加上 2 ,就是 7 的所有组合;
  • 同理考虑 3,如果找到了 7 - 3 = 4 的所有组合,再在之前加上 3 ,就是 7 的所有组合,依次这样找下去;
  • 上面的思路就可以画成下面的树形图。

Gks2TS.png Gkscef.png Gksgw8.png

画出图以后,我看了一下,我这张图画出的结果有 4 个 0,对应的路径是 [[2, 2, 3], [2, 3, 2], [3, 2, 2], [7]],而示例中的解集只有 [[7], [2, 2, 3]],很显然,重复的原因是在较深层的结点值考虑了之前考虑过的元素,因此我们需要设置“下一轮搜索的起点”即可.

  • 去重复
    • 在搜索的时候,需要设置搜索起点的下标 begin ,由于一个数可以使用多次,下一层的结点从这个搜索起点开始搜索;
    • 在搜索起点 begin 之前的数因为以前的分支搜索过了,所以一定会产生重复。
  • 剪枝提速
    • 如果一个数位搜索起点都不能搜索到结果,那么比它还大的数肯定搜索不到结果,基于这个想法,我们可以对输入数组进行排序,以减少搜索的分支;

    • 排序是为了提高搜索速度,非必要;

    • 搜索问题一般复杂度较高,能剪枝就尽量需要剪枝。把候选数组排个序,遇到一个较大的数,如果以这个数为起点都搜索不到结果,后面的数就更搜索不到结果了。

  •   “ 半角空格”

  •   “ 全角空格”

  • <br>换行

代码

class Solution {
public:
    vector<vector<int>> ans;
    vector<int> path;
    void DFS(int start,int target,vector<int> candidates)
    {
        if (target == 0) {
            ans.push_back(path);
            return;
        }
        for(auto i = start;i<candidates.size() && target-candidates[i]>=0;i++) {
            path.push_back(candidates[i]);
            DFS(i,target-candidates[i],candidates);
            path.pop_back();
        }
    }
    vector<vector<int>> combinationSum(vector<int>& candidates, int target)
    {
        sort(candidates.begin(),candidates.end());
        DFS(0,target,candidates);
        return ans;
    }
};


下一篇 动态规划算法

Comments

Content