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

文章介绍了LeetCode中关于组合总和的两道题目(39和40题)的解决方案,主要使用了递归和回溯法。在39题中,允许元素重复选取;而在40题中,元素不可重复选取,需要对数组排序以处理重复元素。另外,还讨论了131题分割回文串的问题,同样利用递归和双指针判断回文。
摘要由CSDN通过智能技术生成

LeetCode 39 组合总和

题目链接:39
思路:由于数组中的元素可重复选取,因此每次选完当前元素后,递归数组的startIndex与当前index相同。
代码:

class Solution {
public:
    vector<int> path;
    vector<vector<int>> result;
    int sum = 0;
    
    void backtracking(vector<int>& candidates, int start, int target) {
        if (sum == target) {
            result.push_back(path);
            return;
        }
        if (sum > target) return;

        for (int i=start; i<candidates.size(); ++i) {
            path.push_back(candidates[i]);
            sum += candidates[i];
            backtracking(candidates, i, target);
            sum -= candidates[i];
            path.pop_back();
        }
    }

    vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
        path.clear();
        result.clear();
        backtracking(candidates, 0, target);
        return result;
    }
};

LeetCode 40 组合总和 II

题目链接:40
思路:数组中的元素不可重复选取,但数组中存在重复元素。为了去重,首先对原数组进行排序,防止由于顺序不同导致的重复。这样,得到的所有组合都将按序排列,且搜索时重复元素一定相邻。在单层递归中,由于元素在同一个组合内可以重复,但两个组合不能重复,因此需避免同一树层的重复,即在for循环中,与前一元素相等的元素不应选取。具体来说,假设当前已选择的组合为 A = { a 1 , ⋯   , a i } A=\{a_1,\cdots,a_i\} A={a1,,ai} ,待选择的数组元素集合 B = { b 1 , b 2 , ⋯   } B=\{b_1,b_2,\cdots\} B={b1,b2,}。本次选择了 b 1 b_1 b1,则通过递归能搜索到由 A ∪ b 1 A\cup b_1 Ab1 开始的所有组合;下次选择 b 2 b_2 b2 时,若 b 1 = b 2 b_1=b_2 b1=b2,则由 A ∪ b 2 A\cup b_2 Ab2 开始的所有组合一定是由 A ∪ b 1 A\cup b_1 Ab1 开始的所有组合的子集,因此会导致重复,此时避免选择 b 2 b_2 b2 即避免同一数层上的遍历。
代码:

class Solution {
public:
    vector<int> path;
    vector<vector<int>> result;
    int sum = 0;

    void backtracking(vector<int>& candidates, int start, int target) {
        if (sum == target) {
            result.push_back(path);
            return;
        }

        for (int i=start; i<candidates.size() && sum+candidates[i] <= target; ++i) {
            if (i > start && candidates[i] == candidates[i-1]) continue;
            path.push_back(candidates[i]);
            sum += candidates[i];
            backtracking(candidates, i+1, target);
            sum -= candidates[i];
            path.pop_back();
        }
    }

    vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
        path.clear();
        result.clear();
        sort(candidates.begin(), candidates.end());
        backtracking(candidates, 0, target);
        return result;
    }
};

LeetCode 131 分割回文串

题目链接:131
思路:分割问题可以看作组合问题的变形。先选取一个分割点,再在分割点右侧子数组中选取下一个分割点,若分割到数组末尾则分割结束。回文串的判断采用双指针法。
代码:

class Solution {
public:
    vector<string> str;
    vector<vector<string>> result;

    bool isPalindrome(string& s) {
        int left = 0;
        int right = s.size()-1;
        while (left < right) {
            if (s[left++] != s[right--]) return false;
        }
        return true;
    }

    void backtracking(string& s, int start) {
        if (start == s.size()) {
            result.push_back(str);
            return;
        }

        for (int i=start+1; i<=s.size(); ++i) {
            string temp(s.begin()+start, s.begin()+i);
            if (!isPalindrome(temp)) continue;
            str.push_back(temp);
            backtracking(s, i);
            str.pop_back();
        }
    }

    vector<vector<string>> partition(string s) {
        str.clear();
        result.clear();
        backtracking(s, 0);
        return result;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值