39. Combination Sum(组合总和)解法(C++ & 注释)

39. Combination Sum(组合总和)

  • 1. 题目描述
  • 2. 回溯法(Backtracking)
    • 2.1 解题思路
    • 2.2 实例代码

1. 题目描述

给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。

candidates 中的数字可以无限制重复被选取。

说明:

  • 所有数字(包括 target)都是正整数。
  • 解集不能包含重复的组合。

示例 1:

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

示例 2:

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

题目链接:中文题目;英文题目

2. 回溯法(Backtracking)

2.1 解题思路

首先这题为什么会用到回溯法呢?我们可以顺着一个例子的解题思路来看看如何想到使用回溯法的:

[2,3,5], target = 8

如果先选择2,需要考察一下只有2能不能揍出8呢?所以我们连续-2,直到差值为0;这时只用2就能得到8,有了第一个答案:

8 -2 - 2 -2 -2 = 0

然后我们会想,2能不能和3揍出8呢?刚才我们用了4个2揍出了8,所以自然而然地,我们把最后一个2替换成3:

8 -2 - 2 -2 -3 = -1

-1小于0了,所以3个2和一个3行不通了,结果太小了,所以3后面更大的5肯定也不行,我们需要回到第三个2上,把它替换成3:

8 -2 - 2 -3 = 1

结果大于0,但是小于所有candidate三的数,所以这种组合也太大了,也不行。之后我们回到第二个2上,替换成3:

8 -2 -3 = 5

如果再-2就和上面答案重复了,所以不能吃回头草,后面继续减-3:

8 -2 -3 -3 = 0

结果又为0了,又得到了一个答案。到此,我们观察一下,这种从后往前,一直往前走,遇到不行的情况,再退回先前某一步的方法,是不是非常像回溯法呢?所以我们可以依据上述的思路进行回溯归纳:

我们规定一个函数f(nums, i, target),nums表示当前candidates的数组,i表示当前candidates的序号,target表示当前需要揍出的数,所以:

  1. 当target - nums[i] < 0 或 i越界,return;
  2. 当target - nums[i] > 0,继续减去nums[i],即f(nums, i, target - nums[i]);
  3. 当target - nums[i],得到一组答案,return;
  4. 考察完2中的nums[i],继续考察下一个数nums[i + 1],即f(nums, i + 1, target)

注意candidates需要先进行升序排序,上述过程才能成立,否则会跳过一些可能的答案组合。如果有童鞋对上述回溯法的流程不是很能理解,可以看看下面的流程图加深理解(图中函数省略了nums参数):

39. Combination Sum(组合总和)解法(C++ & 注释)_第1张图片

2.2 实例代码

class Solution {
     
    vector<vector<int>> ans;
    vector<int> temp;

    void backTracking(vector<int>& nums, int idx, int target) {
     
        if (idx >= nums.size() || target - nums[idx] < 0) return;
        temp.push_back(nums[idx]);
        if (target - nums[idx] == 0) {
      ans.push_back(temp); temp.pop_back(); return; }
        backTracking(nums, idx, target - nums[idx]);
        temp.pop_back();
        backTracking(nums, idx + 1, target);
    }

public:
    vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
     
        sort(candidates.begin(), candidates.end());
        backTracking(candidates, 0, target);
        return this->ans;
    }
};

你可能感兴趣的:(LeetCode-Medium,c++,leetcode)