【算法训练营day27】LeetCode39. 组合总和 LeetCode40. 组合总和II LeetCode131. 分割回文串

  • 阿里云国际版折扣https://www.yundadi.com

  • 阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

    LeetCode39. 组合总和

    题目链接:39. 组合总和

    独上高楼,望尽天涯

    题目不难,注意start_index参数的使用。

    class Solution {
    private:
        vector<vector<int>> result;
        vector<int> path;
        void backtracking(vector<int>& candidates, int target, int start_index) {
            if (target == 0) {
                result.push_back(path);
                return;
            }
            else if (target < 0) {
                return;
            }
            for (int i = start_index; i < candidates.size(); i++) {
                target -= candidates[i];
                path.push_back(candidates[i]);
                backtracking(candidates, target, i); //不用i+1,因为可以无限重复选取
                target += candidates[i];
                path.pop_back();
            }
        }
    public:
        vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
            backtracking(candidates, target, 0);
            return result;
        }
    };
    

    慕然回首,灯火阑珊

    和题解想的一样。

    剪枝操作

    在求和问题中,排序之后加剪枝是常见的套路。

    class Solution {
    private:
        vector<vector<int>> result;
        vector<int> path;
        void backtracking(vector<int>& candidates, int target, int start_index) {
            if (target == 0) {
                result.push_back(path);
                return;
            }
            for (int i = start_index; i < candidates.size() && target - candidates[i] >= 0; i++) { // 剪枝操作
                target -= candidates[i];
                path.push_back(candidates[i]);
                backtracking(candidates, target, i);
                target += candidates[i];
                path.pop_back();
            }
        }
    public:
        vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
            sort(candidates.begin(), candidates.end()); // 需要排序
            backtracking(candidates, target, 0);
            return result;
        }
    };
    

    LeetCode40. 组合总和II

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

    独上高楼,望尽天涯

    本题的难点在于去重,建议回溯问题以后都要在纸上画出清晰的递归树形结构,会对解题有很大帮助!

    慕然回首,灯火阑珊

    都知道组合问题可以抽象为树形结构,那么“使用过”在这个树形结构上是有两个维度的,一个维度是同一树枝上使用过,一个维度是同一树层上使用过。没有理解这两个层面上的“使用过” 是造成大家没有彻底理解去重的根本原因。

    所以我们要去重的是同一树层上的“使用过”,同一树枝上的都是一个组合里的元素,不用去重

    强调一下,树层去重的话,需要对数组排序!

    class Solution {
    private:
        vector<vector<int>> result;
        vector<int> path;
        void backtracking(vector<int>& candidates, int target, int start_index) {
            if (target == 0) {
                result.push_back(path);
                return;
            }
            for (int i = start_index; i < candidates.size() && target - candidates[i] >= 0; i++) {
                if (i > start_index && candidates[i] == candidates[i-1]) { //去重操作
                    continue;
                }
                target -= candidates[i];
                path.push_back(candidates[i]);
                backtracking(candidates, target, i+1);
                target += candidates[i];
                path.pop_back();
            }
        }
    public:
        vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
            sort(candidates.begin(), candidates.end()); //去重需要排序
            backtracking(candidates, target, 0);
            return result;
        }
    };
    

    LeetCode131. 分割回文串

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

    独上高楼,望尽天涯

    很有难度的一道题,需要分别处理切割和判断是否是回文串两个问题。

    慕然回首,灯火阑珊

    切割问题类似组合问题。

    class Solution {
    private:
        vector<vector<string>> result;
        vector<string> path;
        bool isPalindrome(const string& s, int begin, int end) {
            for (int i = begin, j = end; i < j; i++, j--) {
                if (s[i] != s[j]) {
                    return false;
                }
            }
            return true;
        }
        void backtracking(string s, int start_index) {
            // 如果起始位置已经大于s的大小,说明已经找到了一组分割方案了
            if (start_index >= s.size()) {
                result.push_back(path);
                return;
            }
            // for循环横向遍历,寻找所有以start_index为首的回文子串
            for (int i = start_index; i < s.size(); i++) {
                if (isPalindrome(s, start_index, i)) {
                    string str = s.substr(start_index, i - start_index + 1);
                    path.push_back(str);
                    backtracking(s, i + 1);
                    path.pop_back();
                }
            }
        }
    public:
        vector<vector<string>> partition(string s) {
            backtracking(s, 0);
            return result;
        }
    };
    
  • 阿里云国际版折扣https://www.yundadi.com

  • 阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

    “【算法训练营day27】LeetCode39. 组合总和 LeetCode40. 组合总和II LeetCode131. 分割回文串” 的相关文章