【代码随想录|回溯算法02】

39.组合总和

题目链接https://leetcode.cn/problems/combination-sum

自己做的时候在for循环里面循环条件用的是

for(int i=0;i<candidates.size();i++)

发现有重复的元素,在报错,这道题是要数组里元素的和加起来等于target,因为是组合问题,排列是没有顺序的区别的,也就是说不能走回头路,我赋值i=0,那在每一次递归的时候都会从第一个元素开始选,那么比如我上次选的1,2 这次就会选到2,1就肯定会有重复的数组了,所以这里从startindex开始选的话,我每次就都从这个数往后面选,就可以进行正确的递归了 

class Solution {
public:
vector<int> path;
vector<vector<int>> result;
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++){
        path.push_back(candidates[i]);
        sum+=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;
    }
};

40.组合总和||

题目链接https://leetcode.cn/problems/combination-sum-ii

这块代码随想录讲得真的牛,建议直接看视频 

这里代码随想录提出了树枝去重和树层去重,就是这道题,求的组合既要有重复元素,又不能有重复的组合,所以在选的过程里面可以定义一个bool类型的used数组,在竖直方向上的选取是可以重复的,比如

andidates = [1,1,2,3,4], target = 5

我的组合是可以包含有[1,1,3]的,这叫树枝去重

然后假设我第一个1取到的组合[1,4]

那我第二个1肯定也能取到组合[1,4]这样不行,就必须要把这个数过掉,这叫树层去重

也就是我们相同的元素在一个组合里:√

相同元素在不同组合选到了同几个数:×

所以我们定义的used数组就派上了用场,只要有两个相同的数且前一个相同的数没有用过,也就是我们不在一个组合里了,那直接continue吧,就自动把这个数过掉了,代码体现是这个:

if (i>0&&used[i - 1] == 0 && candidates[i] == candidates[i - 1]) {
                    continue;}

class Solution {
public:
    vector<int> path;
    vector<vector<int>> result;
    void backtracking(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++) {
//在循环里面做剪枝,可以少做一次循环

                
               if (i>0&&used[i - 1] == 0 && candidates[i] == candidates[i - 1]) {
                    continue;
                }
            
            sum += candidates[i];
            path.push_back(candidates[i]);
            used[i] = true;
            backtracking(candidates, target, sum, i + 1, used);
            path.pop_back();
            used[i] = false;
            sum -= candidates[i];
        }
    }
    vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
        sort(candidates.begin(), candidates.end());
//排序,让相同元素挨在一起,在后面好进行树层去重
        vector<bool> used(candidates.size(), false);
        backtracking(candidates, target, 0, 0, used);
        return result;
    }
};

131.分割回文串

题目链接https://leetcode.cn/problems/palindrome-partitioning

看这道题的第一印象是我累个乖乖这咋写!??

这道题的思路就是用i和startindex来进行选取子串,因为startindex指向的是传入的第一个数,也就是切割起点,而我的i是可以不断变化的i<s.size()的,所以i就是切割的终点,所以我我只需要判断一下我这个(startindex,i)这个区间里面是不是回文串,只要是回文串我就把他切割下来放到我的path里面,不是的话就回去切割下一个字符。

到最后只要我的startindex都等于数组的最后一个字符后了,那就肯定截止了,往result里面塞就行,这里终止条件没有进行筛选是因为在循环的时候就已经进行剪枝了,你放在path数组里的肯定都是回文串了,那我直接收集你的结果就行。

class Solution {
public:
    vector<string> path;
    vector<vector<string>> result;
    bool Palindrome(string& str, int start, int end) {//判断回文串
        for (int i = start, j = end; i < j; i++, j--) {
            if (str[i] != str[j]) {
                return false;
            }
        }
        return true;
    }
    void backtracking(string& s, int startindex) {
        if (startindex == s.size()) {//单次递归终止条件
            result.push_back(path);
            return;
        }
        for (int i = startindex; i < s.size(); i++) {
            if (Palindrome(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();
        }
    }
    vector<vector<string>> partition(string s) {
        backtracking(s, 0);
        return result;
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值