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

本文介绍了LeetCode中的三个问题,分别是组合总和、组合总和II(去重版本)和分割回文串,通过回溯算法实现,涉及剪枝、去重策略以及分割过程的逻辑设计。
摘要由CSDN通过智能技术生成

39. 组合总和

题目链接:39. 组合总和

文档讲解:代码随想录

视频讲解:带你学透回溯算法-组合总和(对应「leetcode」力扣题目:39.组合总和)| 回溯法精讲!

思路

77.组合问题类似,只需定义一个全局变量sum记录当前路径的和,sum等于target时,将该路径添加至结果数组。

剪枝:对数组进行排序,然后使用回溯算法,当sum大于target时,结束当次循环。

代码

class Solution {
public:
	vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
		result.clear();
		path.clear();
		sort(candidates.begin(), candidates.end());
		backtracking(candidates, target, 0);
		return result;
	}

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

		if (sum > target)
			return;

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

40.组合总和II

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

文档讲解:代码随想录

视频讲解:回溯算法中的去重,树层去重树枝去重,你弄清楚了没?| LeetCode:40.组合总和II

思路

首先排序数组,然后进行回溯,回溯时需要在横向方向上进行去重,纵向方向不去重。

定义一个used变量,其中每一位代表数组中对应下标位置的数是否用过,当candidates[i] == candidates[i-1]时,判断used[i-1]是否为0,若为0,表示当前数的前一个数没用过,即横向方向上,跳过此次循环;若为1,表示当前数的前一个数用过,即纵向方向上,不进行去重操作。

代码

class Solution {
public:
    vector<vector<int>> combinationSum2(vector<int> &candidates, int target) {
        used.resize(candidates.size());
        sort(candidates.begin(), candidates.end());
        backtracking(candidates, 0, target);
        return result;
    }

private:
    vector<vector<int>> result;
    vector<int> path;
    vector<bool> used;
    int sum;
    void backtracking(vector<int> &candidates, int startIndex, int target) {
        if (sum == target) {
            result.push_back(path);
            return;
        }

        if (sum > target)
            return;

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

131.分割回文串

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

文档讲解:代码随想录

视频讲解:带你学透回溯算法-分割回文串(对应力扣题目:131.分割回文串)| 回溯法精讲!

思路

该题为分割题型,但与组合题型类似,组合题是选择某个下标的元素,而分割题是选择某个下标之前的元素。

横向方向上,选择不同切割位置;纵向方向上,进行下一次切割。

代码

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

private:
    bool judge(string s) {
        if (s == "")
            return false;
        for (int i = 0, j = s.size() - 1; i <= j; i++, j--) {
            if (s[i] != s[j])
                return false;
        }
        return true;
    }

    vector<vector<string>> result;
    vector<string> path;
    int len;
    int sub_len;
    void backtracking(string s, int startIndex) {
        if (sub_len == s.size()) {
            result.push_back(path);
            return;
        }

        if (len == s.size())
            return;

        for (int i = startIndex; i < s.size(); i++) {
            string sub_s = s.substr(startIndex, i - startIndex + 1);
            len += sub_s.size();
            if (judge(sub_s)) {
                path.push_back(sub_s);
                sub_len += sub_s.size();
            }
            backtracking(s, i + 1);
            len -= sub_s.size();
            if (judge(sub_s)) {
                path.pop_back();
                sub_len -= sub_s.size();
            }
        }
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值