代码随想录算法训练营第23天|39. 组合总和、 40.组合总和II、131.分割回文串

39. 组合总和

题目链接:39. 组合总和

思想:套模板,递归逻辑中的for循环里下一层的递归函数参数开始位置和这一层的参数位置一样,保证同一个数字可以无限制重复被选取。

class Solution {
public:

vector<vector<int>> result;
vector<int> path;  
    
    void backtracking(int target,int index,vector<int>& candidates){
        //结束条件
        if(target==0){
            result.push_back(path);
            return;
        }
        //if(target<0) return;

        for(int i = index; i<candidates.size()&& target>=0;i++){
            path.push_back(candidates[i]);
            backtracking(target-candidates[i],i,candidates);
            path.pop_back();
        }
    }

    vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
        backtracking(target,0,candidates);
        return result;
    }

};

40.组合总和II

题目链接:40. 组合总和 II

思想:首先需要排序,在递归的单层逻辑中,要对于数字重复的情况进行筛选。如果当前编号为1,前一个编号也为1,则需要分情况讨论。如果是在同一层(即同一个for循环)中访问到的,那么前一个1所获得的数组已经包含了当前1可获得的所有情况,甚至还包含了这个1本身,所以应该跳过当前的1.但如果是在下一层循环中遇到了当前的1,说明这两个1是在同一个组合中出现的,这并不冲突,比如说[1,1],该情况是合法的,不需要跳过。这就是所谓的树层遍历和树枝遍历。为了区分这两种情况,我们可以在回溯中设置一个bool类型的数组来储存当前的访问情况,如果位置i和位置i-1的值相同,而且位置i对应的bool为1,说明i-1这个值被访问过了,为树枝遍历,可以继续。如果bool为0,则说明当前为树层遍历,当前答案数组中并未包含前一个i,所以i的全部情况以及被前一个i包括了,则跳过当前的遍历,i直接+1.

class Solution {
public:
vector<vector<int>> result;
vector<int> path;


    void backtracking(int index, int target, vector<int>& candidates, vector<bool> verify){
        if(target==0){
            result.push_back(path);
            return;
        }
        if(target<0)return;
        //树层和树枝,如果前后两个数相同 而且前一个数为0,则说明这两个值在同一层,此时应该跳过
        //如果前一个数为1,则说明这两个值在同一个树枝上,符合条件,不用跳过。
        for(int i = index;i<candidates.size();i++){
            verify[i] = 1;
            if(i>0&&candidates[i]==candidates[i-1]&&verify[i-1]==0){
                verify[i]=0;
                continue;
            }
            path.push_back(candidates[i]);
            backtracking(i+1,target-candidates[i],candidates,verify);
            path.pop_back();
            verify[i] = 0;
        }
    }
    vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
        vector<bool> verify(candidates.size(),0);
        sort(candidates.begin(),candidates.end());
        backtracking(0,target,candidates,verify);
        return result;
    }
};

131.分割回文串

题目链接:131. 分割回文串

思想:在插入答案数组之前首先要判断当前字符串是不是回文串,所以应该写一个判断回文串的函数,如果满足条件的话则进行插入。结束条件:当前访问的位置大于等于总字符串的长度。其他地方也是直接套模板就可以。如果字串当前不满足回文串时,就会一直回退,所以不需要担心出现不满足每个子串都是回文串的情况。

难点:不知道怎么初始化字串,搜了一下,string s1 = s.substr(index, i - index + 1)。

class Solution {
public:
vector<string> path;
vector<vector<string>> result;

bool judge(string s){
    for(int i = 0;i<s.size()/2;i++){
        if(s[i]!=s[s.size()-1-i]) return false;
    }
    return true;
}

void backtracking(string s,int index){
   // if(index>s.size()) return;
    if(index>=s.size()){
        result.push_back(path);
        return;
    }
    int start = index;

    for(int i =index;i<s.size();i++){
        string s1 = s.substr(index, i - index + 1);
        
        if(judge(s1)){
            path.push_back(s1);
            backtracking(s,i+1);
            path.pop_back();
        }
    }
}
    vector<vector<string>> partition(string s) {
        backtracking(s,0);
        return result;
    }
};

  • 7
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值