LeetCode刷题day11——回溯法

40.组合总和Ⅱ

给定一个候选人编号的集合 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。

candidates 中的每个数字在每个组合中只能使用 一次

**注意:**解集不能包含重复的组合。

示例 1:

输入: candidates = [10,1,2,7,6,1,5], target = 8,
输出:
[
[1,1,6],
[1,2,5],
[1,7],
[2,6]
]

示例 2:

输入: candidates = [2,5,2,1,2], target = 5,
输出:
[
[1,2,2],
[5]
]

提示:

  • 1 <= candidates.length <= 100
  • 1 <= candidates[i] <= 50
  • 1 <= target <= 30

代码:

开心的写完,发现172/176,最后测试:[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],target =30.内存超过限制

class Solution {
public:
    vector<vector<int>> res;
    vector<int> combine;
    void backtracking(vector<int>& candidates, int &target,int index,int& sum){
        if(sum==target){
            res.push_back(combine);
            return;
        }
        if(sum>target)
        return;
        for(int i=index;i<candidates.size();i++){
            sum+=candidates[i];
            combine.push_back(candidates[i]);
            backtracking(candidates,target,i+1,sum);
            sum-=candidates[i];
            combine.pop_back();
        }
    }
    void remove(vector<vector<int>> &res){//去重
        set<vector<int>> a;
        for(auto & v:res){
            sort(v.begin(),v.end());
            a.insert(v);
        }
        res.assign(a.begin(),a.end());
    }
    vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
        int sum=0;
        for(int i=0;i<candidates.size();i++){
            sum+=candidates[i];
        }
        if(sum<target)
            return res;
        sum=0;
        backtracking(candidates,target,0,sum);
        remove(res);
        return res;
    }
};

发现是没剪枝优化

class Solution {
public:
    vector<vector<int>> res;
    vector<int> combine;
    void backtracking(vector<int>& candidates, int &target,int index,int& sum){
        if(sum==target){
            res.push_back(combine);
            return;
        }
        if(sum>target)
        return;
        for(int i=index;i<candidates.size();i++){
            if(i>index&&candidates[i]==candidates[i-1])//剪枝,如果不写这个,会内存超限。原因是该搜索分枝重复,直接跳过
            continue;
            if(target<candidates[i])//剪枝,候选数字比目标更大,并且已经排好序了,后续只会越来越大。
                break;
            sum+=candidates[i];
            combine.push_back(candidates[i]);
            
            backtracking(candidates,target,i+1,sum);
            sum-=candidates[i];
            combine.pop_back();
        }
    }
    void remove(vector<vector<int>> &res){//优化之后,不用再这样去重
        set<vector<int>> a;
        for(auto & v:res){
            sort(v.begin(),v.end());
            a.insert(v);
        }
        res.assign(a.begin(),a.end());
    }
    vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
        int sum=0;
        for(int i=0;i<candidates.size();i++){
            sum+=candidates[i];
        }
        if(sum<target)
            return res;
        sum=0;
        sort(candidates.begin(),candidates.end());
        backtracking(candidates,target,0,sum);
     //  remove(res);
        return res;
    }
};

131.分割回文串

给你一个字符串 s,请你将 s 分割成一些子串,使每个子串都是

回文串

。返回 s 所有可能的分割方案。

示例 1:

输入:s = "aab"
输出:[["a","a","b"],["aa","b"]]

示例 2:

输入:s = "a"
输出:[["a"]]

提示:

  • 1 <= s.length <= 16
  • s 仅由小写英文字母组成

代码:

这道题,要解决两个问题?

  • 怎么判断是不是回文串——双指针法即可
  • 每一个答案都被穷举,说明要用回溯法,怎么用?

要清楚,正在处理pre=s.substr(0,i);的和未处理的s.substr(i),看清楚,想清楚再用回溯法。

class Solution {
public:
    vector<vector<string>> res;
    vector<string> combine;

    bool isHui(const string & pre) {//双指针法
        int i=0;
        int j=pre.length()-1;
        while(i<=j) {
            if(pre[i]!=pre[j]) {
                return false;
            }
            i++;
            j--;
        }
        return true;
    }

    void backtracking(string s) {
        if(s.size() == 0) {
            res.emplace_back(combine);
            return;
        }
        for(int i = 1; i <= s.length(); i++) {
            string pre=s.substr(0,i);//正要处理的
            if(isHui(pre)) {
                combine.push_back(pre);
                backtracking(s.substr(i));//递归去看未处理的
                combine.pop_back();
            }

        }
    }

    vector<vector<string>> partition(string s) {
        if(s.length()==1) {//优化
            combine.emplace_back(s);
            res.emplace_back(combine);
            return res;
        }
        backtracking(s);
        return res;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值