【代码随想录_Day19】39. 组合总和 40.组合总和II131.分割回文串

以下是今日份的总结

39 组合总和
40 组合总和II
131 分割回文串

如何理解回溯法

回溯法解决的问题都可以抽象为树形结构,指的是所有回溯法的问题都可以抽象为树形结构!
因为回溯法解决的都是在集合中递归查找子集,集合的大小就构成了树的宽度,递归的深度就构成了树的深度。
递归就要有终止条件,所以必然是一棵高度有限的树(N叉树)。

今天的题目难度不低,尽量还是写一些简洁代码 ^ _ ^

组合总和

思路:

数组内数字可以重复,所以回溯的要求是target减去当前数值的差

值得注意的是

减法需要判断元素数值比目标数值大的情况,以及当前回溯法在做减法的时候适用于有序的情况
无重复元素,不考虑数组去重的情况

递归

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

        // 递归
        for (int i = start; i < candidates.size(); i++) {
            if (target - candidates[i] < 0)
                return;
            else {
                target -= candidates[i];
                path.push_back(candidates[i]);
                backTack(candidates, target,i); // 因为数字可以重复所下位可从自生再出发
                path.pop_back();
                target += candidates[i];
            }
        }
    }
    vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
        // 判空
        if (candidates.size() == 0)
            return vector<vector<int>>();
        sort(candidates.begin(),candidates.end());//在有序的前提下
        backTack(candidates, target, 0);
        return res;
    }

组合总和II

思路:

回溯法,和上一题思路一样

值得注意的是

出现重复元素需要考虑去重问题

递归

    vector<vector<int>> res;
    vector<int> path;
    void backTack(vector<int>& candidates, int target, int start) {
        // 结束条件
        if (target == 0) {
            res.push_back(path);
            return;
        }
        // 递归
        for (int i = start; i < candidates.size(); i++) {
            if(i>start&&candidates[i] == candidates[i-1]){
                continue;
            }
            if (target - candidates[i] < 0) {
                return;
            } 
            else {
                target -= candidates[i];
                path.push_back(candidates[i]);
                backTack(candidates, target,i + 1); // 因为数字可以重复所下位可从自生再出发
                path.pop_back();
                target += candidates[i];
            }
        }
    }
    vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
        // 判空
        if (candidates.size() == 0)
            return vector<vector<int>>();
        sort(candidates.begin(), candidates.end()); // 在有序的前提下
        backTack(candidates, target, 0);

        return res;
    }

分割回文串

思路:

切割问题可以抽象为组合问题
如何模拟那些切割线
切割问题中递归如何终止
在递归循环中如何截取子串
如何判断回文

值得注意的是

判断回文串
分割字符串,类似于组合问题,但是递归时增长的是分割的长度

递归

    // 判断回文串
    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;
    }
    vector<vector<string>> res;
    vector<string> path; // 放已经回文的子串
    void backtrack(const string& s, int start) {
        // 如果起始位置已经大于s的大小,说明已经找到了一组分割方案了
        if (start >= s.size()) {
            res.push_back(path);
            return;
        }
        for (int i = start; i < s.size(); i++) {
            if (isPalindrome(s, start, i)) { // 是回文子串
                // 获取[startIndex,i]在s中的子串
                string str = s.substr(start, i - start + 1);
                path.push_back(str);
            } else { // 如果不是则直接跳过
                continue;
            }
            backtrack(s, i + 1); // 寻找i+1为起始位置的子串
            path.pop_back(); // 回溯过程,弹出本次已经添加的子串
        }
    }
    vector<vector<string>> partition(string s) {
        backtrack(s, 0);
        return res;
    }

写在最后

----OK,今日份的博客就写到这里,这一期的回溯法很巧秒啊,也涉及到,明天继续加油!!!
—看了看下期的题,但是我的栈还有一节没写;
–追上时间进度了吗?如追,从欠三天变成欠二天!!(笑
-青梅汁快酿好了,一起喝吧。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值