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

  1. 组合总和
点击查看代码
class Solution {
public:
    vector<vector<int>> result;
    vector<int> path;
    void backtracking(vector<int>& candidates, int &target, int sum, int startIndex) {
        //由于for循环条件已经提前做了递归终止判断,故这里不用再加
        //if(sum > target) return;
        if(sum == target) {
            result.push_back(path);
        }

        //&& sum + candidates[i] <= sum,剪枝,由于candidates数组经过排序
        //故若上一层传下来的sum + 本层的某一元素已经大于target,则+本元素的后
        //续元素也必然大于target,故提前结束本层循环遍历,也不再往下递归
        for(int i = startIndex; i < candidates.size() && sum + candidates[i] <= target; ++i) {
            path.push_back(candidates[i]);
            //下一层的startIndex仍为i,因为同一个数字可重复选取
            backtracking(candidates, target, sum + candidates[i], i);
            path.pop_back();
        }
    }
    vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
        //先排序,方便后续剪枝
        sort(candidates.begin(), candidates.end());
        backtracking(candidates, target, 0, 0);
        return result;
    }
};

注意本题的剪枝操作,同时注意当题目可以重复选取某一元素时,传入下一层函数的startIndex值的选取

40.组合总和II
去重解法一:使用used数组

点击查看代码
class Solution {
public:
    vector<vector<int>> result;
    vector<int> path;
    vector<bool> used;
    void backtracking(vector<int>& candidates, int &target, int sum, int startIndex) {
        if(sum == target) {
            result.push_back(path);
            return;
        }

        for(int i = startIndex; i  < candidates.size() && sum + candidates[i] <= target; ++i) {
            //去重逻辑:树枝不去重,树层去重
            if(i > 0 && candidates[i] == candidates[i - 1] && used[i - 1] == false) continue;
            path.push_back(candidates[i]);
            used[i] = 1;
            //此处i+1是因为candidates中的每个数字在每个组合中只能使用一次
            backtracking(candidates, target, sum + candidates[i], i + 1);
            used[i] = 0;
            path.pop_back();
        }
    }
    vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
        used.resize(candidates.size(), false);
        sort(candidates.begin(), candidates.end());
        backtracking(candidates, target, 0, 0);
        return result;
    }
};

去重解法二:直接使用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) {
            result.push_back(path);
            return;
        }

        for(int i = startIndex; i  < candidates.size() && sum + candidates[i] <= target; ++i) {
            //去重逻辑:树枝不去重,树层去重
            //i = startIndex为本树层的第一个元素,不可能重复,若此时
            //candidates[i] == candidates[i - 1],说明是树枝上的重复,无需去重
            //当i > startIndex且candidates[i] == candidates[i - 1],此时才是树层上重复,需要去重
            if(i > startIndex && candidates[i] == candidates[i - 1]) continue;
            path.push_back(candidates[i]);
            //此处i+1是因为candidates中的每个数字在每个组合中只能使用一次
            backtracking(candidates, target, sum + candidates[i], i + 1);
            path.pop_back();
        }
    }
    vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
        sort(candidates.begin(), candidates.end());
        backtracking(candidates, target, 0, 0);
        return result;
    }
};

131.分割回文串

点击查看代码
class Solution {
public:
    vector<vector<string>> result;
    vector<string> path;

    bool isHuiWen(string &s, int left, int right) {
        while(left < right) {
            if(s[left] != s[right]) return false;
            left++;
            right--;
        }
        return true;
    }

    void backtracking(string &s, int startIndex){
        if(startIndex == s.size()) {  //能到达这个if判断的说明已切的均为回文串,否则不会递归到这
            result.push_back(path);
            return;
        }

        for(int i = startIndex; i < s.size(); ++i) {
            if(isHuiWen(s, startIndex, i)) {
                path.push_back(s.substr(startIndex, i - startIndex + 1));
            }
            else continue; //不是回文串则继续往后切,不进行递归,是回文串才往下递归
            backtracking(s, i + 1);
            path.pop_back();
        }
    }

    vector<vector<string>> partition(string s) {
        backtracking(s, 0);
        return result;
    }
};

每一层for循环中,[startIndex, i]区间即为所切割的区间,需要判断这个区间的子串是否为回文串,是的话则放入path中,不是的话再往后切割

2025/03/05

posted @ 2025-03-05 23:23  coder小杰  阅读(17)  评论(0)    收藏  举报