day27 代码回想录 组合总和&组合总和II&分割回文串

大纲

  1. 组合总和
    ● 40.组合总和II
    ● 131.分割回文串

组合总和

题目:39. 组合总和

// 39 组合数
// 使用递归+回溯
// 确定参数返回值:数组,目标值,开始下标值,返回void
// 确定结束条件:和>目标值、开始下标大于数组个数
// 单层循环:不断从index 到数组结尾的回溯循环
int sum = 0;
vector path;
vector> ret;
void _combineNumber(vector& candidates, int target, int startIndex)
{
    if (sum > target) return;
    if (sum == target) {
        ret.push_back(path);
        return;
    }
    for (int i = startIndex; i < candidates.size(); ++i) {
        sum += candidates[i];
        path.push_back(candidates[i]);
        _combineNumber(candidates, target, i);
        path.pop_back();
        sum -= candidates[i];
    }
}
vector> combineNumber(vector& candidates, int target)
{
    _combineNumber(candidates, target, 0);
    return ret;
}

40.组合总和II

题目:40.组合总和II

// 40 组合数2
// 需要对数组排序,再进行combineNumber
// 需要去除重复项:对重复开始进行过滤
// 总结:思路是对的,但是怎么跳过重复元素没有考虑到位
void _combinationSum2(vector& candidates, int target, int startIndex) {
    if (sum > target) {
        return;
    }
    if (sum == target) {
        ret.push_back(path);
        return;
    }

    for (int i = startIndex; i < candidates.size(); ++i) {
        // 跳过重复组合
        if (i > startIndex && candidates[i - 1] == candidates[i]) {
            continue;
        }
        sum += candidates[i];
        path.push_back(candidates[i]);
        _combinationSum2(candidates, target, i + 1);
        path.pop_back();
        sum -= candidates[i];
    }
}

vector> combinationSum2(vector& candidates, int target) {
    sort(candidates.begin(), candidates.end());
    _combinationSum2(candidates, target, 0);
    return ret;
}

131.分割回文串

题目:131.分割回文串

// 判断是否回文函数写错误了
// 问题1:right = s.size()
// 问题2:++ --没有做
bool isHuiWen(string s) {
    int left = 0, right = s.size() - 1;
    while (left < right) {
        if (s[left++] != s[right--])
            return false;
    }
    return true;
}

// startIndex 是分割线
void subHuiWen(string &s, int startIndex) {
    // 满足分割线到达末尾了
    if (startIndex == s.size() - 1) {
        ret1.push_back(path1);
        return;
    }
    // 不断划分剩下的字符串
    for (int i = startIndex; i < s.size(); ++i) {
        // 取子串
        string tmp = s.substr(startIndex, i - startIndex + 1);
        if (!isHuiWen(tmp)) {
            continue;
        }

        path1.push_back(tmp);
        subHuiWen(s, i);
        path1.pop_back();
    }
}

vector> partition(string s) {
    subHuiWen(s, 0);
    return ret1;
}

总结

回溯题解法有一定规律性,通过递归可以减少一层循环,将题目的解法抽象为二叉树,树的高度代表递归的深度,树的宽度代表循环选择。

你可能感兴趣的:(c++,算法,回溯)