思路:
本题难就难在,如何避免第二次使用到我们重复的数组。基本思路
1、依次遍历传入进来的数组,从第一个值开始遍历
2、用一个全局变量sum来统计和,若等于目标值,说明已经找到合适的数组,并将其加入到result结果数组中
3、在回溯的过程中,为了避免出现重复出现的元素,其起始位置应改为当前遍历位置也就是i值,这样才能避免又反过去重新来一遍。
最后依次往复。
class Solution {
private:
vector<vector<int>>result;
void backtracking(vector<int>&condidates,int target,vector<int>&pathvary,int &sum,int startIndex)
{
if (sum == target)
{
result.push_back(pathvary);
return;
}
if (sum > target)return;
//其中有一个终止条件的判断
for (int i = startIndex; i < condidates.size(); i++)//必须得控制一个大小,这样才能方便其完成一定的值,才能不是无限往下循环。//此代码会出现一种情况,排序顺序的出现,要避免这种情况
{
pathvary.push_back(condidates[i]);
sum += condidates[i];
if (sum <= target) {
backtracking(condidates, target, pathvary, sum,i);//这里需要对自己的I进行一个进入,这样才能避免出现重复的操作
}
pathvary.pop_back();
sum -= condidates[i];
}
}
public:
vector<vector<int>> combinationSum(vector<int>& candidates, int target)
{
int sum = 0;
vector<int>pathvary;
backtracking(candidates, target, pathvary, sum,0);
return result;
}
};
思路:
一开始认为本题跟39差不多,自己先对数组进行了排序,然后再去除重复元素,但发现会删除掉一些符合条件的元素,才发现出问题了,也就是不知道如何动态的去重。后面看卡哥的才发现应该如何去重。
树形重复和树层重复,这里是不能采用树层重复的。
1、为每一个candidates数组都设置一个标签位,若此数正在使用,将标签置为true,若未使用置为false。
2、在这里我们应该知道如何去重,对candidates拍完序之后,倘若遇到前后两数都相同,并且需要判断标签位数组的[i-1]是否为false,如果为false,那么我们将直接跳过此数,因为在之前,我们就基于此数进行了组合,
3、若我们在用此数,相当于又进行了一次组合,也就是前者数的组合是包含后者数的组合。
4、每个数只能使用一次,所以我们startIndex=i+1.
class Solution {
private:
vector<vector<int>>result;
void backtracking(vector<int>& condidates, int target, vector<int>& pathvary, int& sum, int startIndex,vector<bool>&used)
{
if (sum == target)
{
result.push_back(pathvary);
return;
}
if (sum > target)return;//有了这一段,就可以返回了
//其中有一个终止条件的判断
for (int i = startIndex; i < condidates.size(); i++)//必须得控制一个大小,这样才能方便其完成一定的值,才能不是无限往下循环。//此代码会出现一种情况,排序顺序的出现,要避免这种情况
{
if (i > 0 && condidates[i - 1] == condidates[i] && used[i - 1] == false) continue;
sum += condidates[i];
pathvary.push_back(condidates[i]);
used[i] = true;
if(sum<=target)
{
backtracking(condidates, target, pathvary, sum, i +1,used);//这里需要对自己的I进行一个进入,这样才能避免出现重复的操作
}
used[i] = false;
pathvary.pop_back();
sum -= condidates[i];
}
}
public:
vector<vector<int>> combinationSum2(vector<int>& candidates, int target)
{
vector<bool>used(candidates.size(), false);
int sum = 0;
vector<int>pathvary;
sort(candidates.begin(), candidates.end());
backtracking(candidates, target, pathvary, sum, 0,used);
return result;
}
};
不知道大家有没有这种想法,自己想怎么也想不出来,一看卡哥的视频一下子就能写出来,就是一下子就能理解题目的做法。这可能就是眼高手低。
本题难点,如何切割,一步一步切割问题是一个难点,
采用的
substr(startIndex,i-startIndex+1)
这句语句的意思是,从传入的startIndex开始,随着I每加一,我就取一段出来,然后放入判断是否否回文子串的函数 isPalindrome(const string& s, int start, int end)中
bool isPalindrome(const string& s, int start, int end) {
for (int i = start, j = end; i < j; i++, j--) {
if (s[i] != s[j]) {
return false;
}
}
return true;
}
若满足,那么我就对path进行添加。不满足就跳过。
回溯的终止条件为:开始位置大于等于字符串的长度,说明我已经全部遍历完
因为我每一次的这个判断都是对我上一层的一个判断。
其次这是对一个字符串,从左到右,分别取一个,再取两个,依次叠加,直到全部取完。
class Solution {
private:
vector<vector<string>>result;
vector<string>path;
void backtracking(const string& s, int startIndex)
{
//如果当前传入的起始位置比s的长度还长,或者相等,说明已经检索完毕,已经找到合适的分割方案
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(const string& s, int start, int end) {
for (int i = start, j = end; i < j; i++, j--) {
if (s[i] != s[j]) {
return false;
}
}
return true;
}
public:
vector<vector<string>> partition(string s) {
result.clear();
path.clear();
backtracking(s, 0);
return result;
}
};