1、LeetCode39组合总和
题目链接:39、组合总和
本题由于每次递归要从第一个元素开始递归,而且可以重复,终止条件不再判断path.size()==k,startIndex递归时也不用每次+1。
class Solution {
public:
vector<vector<int>> result;
vector<int> path;
void backstracking(vector<int>& candidates, int target, int sum, int startIndex)
{
if (sum > target) return;
if (sum == target)
{
result.push_back(path);
return;
}
for (int i = startIndex; i < candidates.size(); i++)
{
path.push_back(candidates[i]);
sum += candidates[i];
backstracking(candidates, target, sum, i);
sum -= candidates[i];
path.pop_back();
}
}
vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
result.clear();
path.clear();
if (candidates.size() == 0) return result;
backstracking(candidates, target, 0, 0);
return result;
}
};
去剪枝操作:
对总集合排序之后,如果下一层的sum(就是本层的 sum + candidates[i])已经大于target,就可以结束本轮for循环的遍历。
class Solution {
public:
vector<vector<int>> result;
vector<int> path;
void backstracking(vector<int>& candidates, int target, int sum, int startIndex)
{
if (sum == target)
{
result.push_back(path);
return;
}
for (int i = startIndex; i < candidates.size() && sum + candidates[i] <= target; i++)
{
path.push_back(candidates[i]);
sum += candidates[i];
backstracking(candidates, target, sum, i);
sum -= candidates[i];
path.pop_back();
}
}
vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
result.clear();
path.clear();
sort(candidates.begin(), candidates.end());
if (candidates.size() == 0) return result;
backstracking(candidates, target, 0, 0);
return result;
}
};
2、LeetCode40组合总和II
题目链接:40、组合总和II
例如,[1,1,2] 第一个1和2,第二个1和2,不能重复组合
先排序,如果 candidates[i] == candidates[i-1],说明元素重复,需要判断是否可以添加。
如果在同一树层上使用过,不能添加;
如果在同一树枝上使用过,可以添加。
如何判断是在同一树层还是同一树枝?需要定义一个 vector<bool> used(candidates.size(), false);
当在遍历过程中时,used[i] = true;
当在回溯时,used[i] = false.
那么如果是同一树枝,还没有回溯,当前元素的前一个元素的 used[i-1] == true;
如果used[i-1] == false,说明发生了回溯,此时是从树层开始向后遍历了,continue。
class Solution {
public:
vector<vector<int>> result;
vector<int> path;
void backstracking(vector<int>& candidates, int target, int sum, int startIndex, vector<bool>& used)
{
if (sum == target)
{
result.push_back(path);
return;
}
for (int i = startIndex; i < candidates.size() && sum + candidates[i] <= target; i++)
{
// used[i - 1] == true,说明同一树枝candidates[i - 1]使用过
// used[i - 1] == false,说明同一树层candidates[i - 1]使用过
// 要对同一树层使用过的元素进行跳过
if (i > 0 && candidates[i] == candidates[i-1] && used[i-1] == false)
{
continue;
}
sum += candidates[i];
path.push_back(candidates[i]);
used[i] = true;
backstracking(candidates, target, sum, i + 1, used);
used[i] = false;
path.pop_back();
sum -= candidates[i];
}
}
vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
vector<bool> used(candidates.size(), false);
result.clear();
path.clear();
sort(candidates.begin(), candidates.end());
backstracking(candidates, target, 0, 0, used);
return result;
}
};
3、LeetCode131分割回文串
题目链接:131、分割回文串
终止条件:startIndex >= s.size(),说明startIndex已经遍历到超过元素个数了,已经找到了一组分割方案了。
判断是否是回文串,双指针法,isPalindrome(s, startIndex, i),如果是回文串则添加,如果不是,continue语句可以让i++,判断再添加一个能不能构成回文串,比如“efe”。
截取字符串:s.substr(startIndex, i - startIndex + 1)。
递归和回溯。
class Solution {
public:
vector<vector<string>> result;
vector<string> path;
void backtracking(string& s, int startIndex)
{
if (startIndex >= s.size())
{
result.push_back(path);
return;
}
for (int i = startIndex; i < s.size(); i++)
{
if (isPalindrome(s, startIndex, i))
{
string str = s.substr(startIndex, i - startIndex + 1);
path.push_back(str);
}
else
{
continue;
}
backtracking(s, i + 1);
path.pop_back();
}
}
bool isPalindrome(string& s, int left, int right)
{
for (int i = left, j = right; i < j; i++, j--)
{
if (s[i] != s[j])
{
return false;
}
}
return true;
}
vector<vector<string>> partition(string s) {
result.clear();
path.clear();
backtracking(s,0);
return result;
}
};