代码随想录算法训练营第二十七天 | 题目 39. 组合总和 题目 40.组合总和II 题目 131.分割回文串

39. 组合总和

思路:本题可以存在重复元素,但是答案中具有相同元素,可以顺序不同,也视为同一元素。因此,要让startIndex等于当前答案遍历的起始元素。

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);//从i开始避免和以后得答案重复
            sum -= candidates[i];
            path.pop_back();
        }
    }
    vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
        result.clear();
        path.clear();
        int sum = 0;
        backtracking(candidates, target, sum, 0);
        return result;
    }
};

40.组合总和II

误区:题目要求candidates 中的每个数字在每个组合中只能使用 次 ,但是由于有重复的数字,设置startIndex并不能完全解决这个问题。

此时需要进行排序后去重。

由于回溯分为两部分:for循环遍历(横向),递归遍历(纵向)。纵向遍历是遍历除去当前值后的后面的元素组成的数组,不断重复。

如果原始数组中元素都不重复,那么就可以直接用startIndex进行纵向遍历去重,避免重复的答案集合;

如果原始数组中的元素有重复,那么就需要排序后进行横向遍历去重,跳过原始集合中重复的元素。

40.组合总和II1

    这里使用startIndex去重,在纵向遍历过程,递归时传入startIndex,利用startIndex更新candidates[i]的值。在for循环遍历中,利用i++更新candidates[i]的值,此时更新完后,如果candidates[i] == candidates[i-1],说明相邻元素是相同的,而在candidates[i-1]递归的时候,已经找到符合题目要求的元素组合了,因此candidates[i]不用再次进行递归,因此就利用continue跳过本次循环,从而避免产生重复的答案。

class Solution {
private:
    vector<vector<int>>result; //存放结果
    vector<int>path;
    void backtracking(vector<int>& candidates, int target, int startIndex, int sum){
        //if(sum > target)return;
        if(sum == target){
            result.push_back(path);
            return;
        }
        for(int i = startIndex; i < candidates.size() && sum + candidates[i] <= target; i++){
            if(i > startIndex && candidates[i] == candidates[i-1]){
                continue;
            }
            sum += candidates[i];
            path.push_back(candidates[i]);
            backtracking(candidates, target, i + 1, sum);  //递归
            sum -= candidates[i];  //回溯
            path.pop_back(); // 回溯
        }
    }
public:
    vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
        result.clear();
        path.clear();
        int sum = 0;
        sort(candidates.begin(), candidates.end());
        backtracking(candidates, target, 0, sum);
        return result;
    }
};

 131.分割回文串

回文串:指正向读和反向读都相同的字符串。无论是单词或者短语,如果它在忽略空格、标点符号和字母大小写的情况下从前往后读和从后往前读是一致的,那么它就是一个回文串。

本题是要找到几种分割方式,使得所有被分割的子串都是回文串。 

因此终止条件为

if(startIndex >= s.size()){
    result.push_back(path);
    return;
}

 这意味着一种分割方式的结束。

下面语句是将利用startIndex和i在每层递归遍历中将子串提取出来,并判断该子串是否是回文串。

string str = s.substr(startIndex, i - startIndex + 1);
class Solution {
private:
    vector<vector<string>> result;
    vector<string>path;
    bool isPalindrome(const string& s, int left, int right){
        while(left <= right){
            if(s[left] != s[right]){
                return false;
            }
            left++;
            right--;
        }
        return true;
    }
    void backtracking(const string& s, int startIndex){
        if(startIndex >= s.size()){
            result.push_back(path);
            return;
        }
        //starIndex就是分割线
        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); // 若字符串是回文串,那么将其放入path中
            }else{
                continue;
            }
            backtracking(s, i + 1);
            path.pop_back();
        }
    }
public:
    vector<vector<string>> partition(string s) {
        result.clear();
        path.clear();
        backtracking(s, 0);
        return result;
    }
};

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值