题目描述:给定一个数组candidates
和一个target
整数,找出数组中所有不重复的、和等于target
的所有可能组合。
For example, given candidate set [2, 3, 6, 7] and target 7,
A solution set is:
[
[2, 2, 3],
[7]
]
简单的回溯法即可求得正解。
- 在递归的每一层中都遍历数组的所有值,对每个值进行判断。判断将该值加入状态数组
box
末尾时会如何(和大于、等于、小于target
三种情况),根据几种情况来判断是压入数组继续递归(和小于target
)还是跳过该值(和大于target
)还是找到一个解将其加入解数组(和等于target
)。 - 递归结束后要将压入
box
中的值弹出,以保证状态数组始终是正确的(回溯)。 - 对于这道题来讲,由于给定数组
candidates
是乱序的,因此先将其升序排序能简化问题。
看代码了解更多细节:
class Solution {
private:
vector<int> _candidates;
int _target;
vector<vector<int> > res;
vector<int> box;
public:
vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
this->_candidates = candidates;
sort(this->_candidates.begin(), this->_candidates.end());
this->_target = target;
driver(0);
return res;
}
void driver(int sum) {
for (int i = 0; i < _candidates.size(); ++i) {
if (box.size() > 0 && box.back() > _candidates[i]) {
continue;
} else if (sum + _candidates[i] > _target) {
continue;
} else if (sum + _candidates[i] == _target) {
box.push_back(_candidates[i]);
res.push_back(box);
box.pop_back();
continue;
} else {
box.push_back(_candidates[i]);
driver(sum + _candidates[i]);
box.pop_back();
}
}
}
};
以上代码中的每一层递归都对candidates
数组从头到尾进行遍历,实际上并没有必要,原因在于我们先前已经对candidates
进行升序排序,而结果不包含重复组合,因此每一层遍历,从上一层中压入数组的值的下标开始遍历就行了(也就是保证了box
中的数一定是升序的)。
代码如下:
class Solution {
private:
vector<int> _candidates;
int _target;
vector<vector<int> > res;
vector<int> box;
public:
vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
this->_candidates = candidates;
sort(this->_candidates.begin(), this->_candidates.end());
this->_target = target;
driver(0, 0);
return res;
}
void driver(int sum, int start) {
for (int i = start; i < _candidates.size(); ++i) {
if (sum + _candidates[i] > _target) {
continue;
} else if (sum + _candidates[i] == _target) {
box.push_back(_candidates[i]);
res.push_back(box);
box.pop_back();
continue;
} else {
box.push_back(_candidates[i]);
driver(sum + _candidates[i], i);
box.pop_back();
}
}
}
};