LeetCode 39 组合总和
题目链接:39
思路:由于数组中的元素可重复选取,因此每次选完当前元素后,递归数组的startIndex
与当前index
相同。
代码:
class Solution {
public:
vector<int> path;
vector<vector<int>> result;
int sum = 0;
void backtracking(vector<int>& candidates, int start, int target) {
if (sum == target) {
result.push_back(path);
return;
}
if (sum > target) return;
for (int i=start; i<candidates.size(); ++i) {
path.push_back(candidates[i]);
sum += candidates[i];
backtracking(candidates, i, target);
sum -= candidates[i];
path.pop_back();
}
}
vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
path.clear();
result.clear();
backtracking(candidates, 0, target);
return result;
}
};
LeetCode 40 组合总和 II
题目链接:40
思路:数组中的元素不可重复选取,但数组中存在重复元素。为了去重,首先对原数组进行排序,防止由于顺序不同导致的重复。这样,得到的所有组合都将按序排列,且搜索时重复元素一定相邻。在单层递归中,由于元素在同一个组合内可以重复,但两个组合不能重复,因此需避免同一树层的重复,即在for
循环中,与前一元素相等的元素不应选取。具体来说,假设当前已选择的组合为
A
=
{
a
1
,
⋯
,
a
i
}
A=\{a_1,\cdots,a_i\}
A={a1,⋯,ai} ,待选择的数组元素集合
B
=
{
b
1
,
b
2
,
⋯
}
B=\{b_1,b_2,\cdots\}
B={b1,b2,⋯}。本次选择了
b
1
b_1
b1,则通过递归能搜索到由
A
∪
b
1
A\cup b_1
A∪b1 开始的所有组合;下次选择
b
2
b_2
b2 时,若
b
1
=
b
2
b_1=b_2
b1=b2,则由
A
∪
b
2
A\cup b_2
A∪b2 开始的所有组合一定是由
A
∪
b
1
A\cup b_1
A∪b1 开始的所有组合的子集,因此会导致重复,此时避免选择
b
2
b_2
b2 即避免同一数层上的遍历。
代码:
class Solution {
public:
vector<int> path;
vector<vector<int>> result;
int sum = 0;
void backtracking(vector<int>& candidates, int start, int target) {
if (sum == target) {
result.push_back(path);
return;
}
for (int i=start; i<candidates.size() && sum+candidates[i] <= target; ++i) {
if (i > start && candidates[i] == candidates[i-1]) continue;
path.push_back(candidates[i]);
sum += candidates[i];
backtracking(candidates, i+1, target);
sum -= candidates[i];
path.pop_back();
}
}
vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
path.clear();
result.clear();
sort(candidates.begin(), candidates.end());
backtracking(candidates, 0, target);
return result;
}
};
LeetCode 131 分割回文串
题目链接:131
思路:分割问题可以看作组合问题的变形。先选取一个分割点,再在分割点右侧子数组中选取下一个分割点,若分割到数组末尾则分割结束。回文串的判断采用双指针法。
代码:
class Solution {
public:
vector<string> str;
vector<vector<string>> result;
bool isPalindrome(string& s) {
int left = 0;
int right = s.size()-1;
while (left < right) {
if (s[left++] != s[right--]) return false;
}
return true;
}
void backtracking(string& s, int start) {
if (start == s.size()) {
result.push_back(str);
return;
}
for (int i=start+1; i<=s.size(); ++i) {
string temp(s.begin()+start, s.begin()+i);
if (!isPalindrome(temp)) continue;
str.push_back(temp);
backtracking(s, i);
str.pop_back();
}
}
vector<vector<string>> partition(string s) {
str.clear();
result.clear();
backtracking(s, 0);
return result;
}
};