LeetCode39. 组合总和
题目链接:39. 组合总和 - 力扣(LeetCode)
文章讲解:代码随想录
视频讲解:带你学透回溯算法-组合总和(对应「leetcode」力扣题目:39.组合总和)| 回溯法精讲!_哔哩哔哩_bilibili
思路:其实这道题和前面的组合问题很像,只不过终止的条件需要更改一下,还有就是递归的参数需要更改一下。由于每个结果数组的个数是不一定的,所以终止条件由之前的达到一定个数变为总和是否大于等于需要的和,大于就直接return,如果等于需要push_back进result中,此外,由于可以取重复的,所以在递归的startindex不需要往后移,直接就是i,而不是i+1。
代码:
class Solution {
public:
vector<vector<int>>result;
vector<int>path;
void backtracking(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++){
sum+=candidates[i];
path.push_back(candidates[i]);
backtracking(candidates,target,sum,i);
sum-=candidates[i];
path.pop_back();
}
}
vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
backtracking(candidates,target,0,0);
return result;
}
};
LeetCode40. 组合总和 II
题目链接:40. 组合总和 II - 力扣(LeetCode)
文章讲解:代码随想录
视频讲解:回溯算法中的去重,树层去重树枝去重,你弄清楚了没?| LeetCode:40.组合总和II_哔哩哔哩_bilibili
思路:和上一题不同的地方在于,比如这个候选数组中有两个1,一个7,要凑成8,如果不去重,就会有两个[1,7],这时候我们的做法是用一个used数组,来标记每个数字是否被使用过,首先需要对数组进行排序,使重复的数字都挨在一起,然后呢,我们在for循环中加这么一个判断:如果遇到和前一个一样的数字,再看前一个的used是否为false,如果是,就直接跳过。那么为什么要判断前一个used是否为false呢,因为如果为true的话,可能会是[1,1,6]这种情况,我们不能把这种情况去重了。
代码:
class Solution {
public:
vector<vector<int>>result;
vector<int>path;
void backtracking(vector<int>& candidates,int target,int sum,int startindex,vector<int>& used){
if(sum>target){
return;
}
if(sum==target){
result.push_back(path);
return;
}
for(int i=startindex;i<candidates.size();i++){
if(i>0&&candidates[i]==candidates[i-1]&&used[i-1]==false){
continue;
}
sum+=candidates[i];
path.push_back(candidates[i]);
used[i]=true;
backtracking(candidates,target,sum,i+1,used);
used[i]=false;
sum-=candidates[i];
path.pop_back();
}
}
vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
sort(candidates.begin(),candidates.end());
vector<int>used(candidates.size(),false);
backtracking(candidates,target,0,0,used);
return result;
}
};
LeetCode131. 分割回文串
题目链接:131. 分割回文串 - 力扣(LeetCode)
文章讲解:代码随想录
视频讲解:带你学透回溯算法-分割回文串(对应力扣题目:131.分割回文串)| 回溯法精讲!_哔哩哔哩_bilibili
思路:这道题比较复杂,首先确定主要函数的参数,一个是串,一个是分割的起始位置,然后终止条件是分割的起始位置大于等于串的大小,这样就把path保存到result中。主要的循环是分割操作,首先i=startindex,此时分割的子串长度为1,然后之后i往后走,扩大子串长度,此时在每次分割子串时,我们都需要调用isPalidrome函数判断一下这个子串是否回文,如果回文就把这个子串加入到path中,如果不回文就跳过。
代码:
class Solution {
public:
vector<string>path;
vector<vector<string>>result;
void backtracking(const string& s,int startindex){
if(startindex>=s.size()){
result.push_back(path);
}
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(const string& s,int begin,int end){
for(int i=begin,j=end;i<j;i++,j--){
if(s[i]!=s[j]){
return false;
}
}
return true;
}
vector<vector<string>> partition(string s) {
backtracking(s,0);
return result;
}
};