20210325:力扣递归,回溯类型题目合集

力扣递归,回溯类型题目合集

题目

    1. 子集

在这里插入图片描述
2. 90. 子集 II
在这里插入图片描述
3. 40. 组合总和 II
在这里插入图片描述
4. 22. 括号生成
在这里插入图片描述

思路与算法

    1. 子集:注释的很详细,递归生成子集。还有一种位运算的方法更加简洁,但是如果不熟练的话会比较吃力。
    1. 子集 II: 其余思路同上题,总体不同在于通过排序去除乱序相同的子集,再通过set去重即可。
    1. 组合总和 II:还是在上一题的基础上,继续增加条件,在递归获取所有子集的同时,利用题目要求的target进行剪枝。
    1. 括号生成:也是此类递归代码的同类思路,重在理解这个过程。发现很久之前提交的Java版本注释的比较详细,cpp的也附上

代码实现

    1. 子集
class Solution {
public:
    vector<vector<int>> subsets(vector<int>& nums) {
        vector<vector<int>> result;
        vector<int> item;
        // 一开始需要加入一个空集先
        result.push_back(item);
        generate(0,nums,item,result);
        return result;
    }

public:
    // 从nums[n]开始,一个一个选择放入item或者不放入item的加入result来获得所有子集
    void generate(int n,vector<int> &nums,vector<int> &item,vector<vector<int>> &result){
        if (n >= nums.size()) {
            return;
        }
        // 将nums[0]加入item,再放入result
        item.push_back(nums[n]);
        result.push_back(item);
        generate(n + 1,nums,item,result);
        // 或者不加入item,直接放入result
        item.pop_back();
        generate(n + 1,nums,item,result); 
    }
};
    1. 子集 II
class Solution {
public:
    vector<vector<int>> subsetsWithDup(vector<int>& nums) {
        vector<vector<int>> result;
        vector<int> item;
        set<vector<int>> res_set;
        // 排序就可以去除顺序不同的相同子集,方便后续使用set进行去重
        sort(nums.begin(),nums.end());
        result.push_back(item);
        generate(0,nums,result,item,res_set);
        return result;
    }

private:
    void generate (int i,vector<int> & nums,vector<vector<int>> &result,vector<int> &item,set<vector<int>> &res_set) {
        if (i >= nums.size()) {
            return;
        }
        item.push_back(nums[i]);
        if (res_set.find(item) == res_set.end()) {
            result.push_back(item);
            res_set.insert(item);
        }
        generate(i + 1,nums,result,item,res_set);
        item.pop_back();
        generate(i + 1,nums,result,item,res_set);
    }
};
    1. 组合总和 II
class Solution {
public:
    vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
        vector<vector<int>> result;
        vector<int> item;
        set<vector<int>> res_set;
        sort(candidates.begin(),candidates.end());
        generate(0,candidates,result,item,res_set,0,target);
        return result;
    }

private:
    void generate(int i,vector<int> &nums,vector<vector<int>> &result,vector<int> &item,set<vector<int>> &res_set,int sum,int target){
        if (i >= nums.size() || sum > target) {
            return;
        }
        sum += nums[i];
        item.push_back(nums[i]);
        if (  (target == sum) && res_set.find(item) == res_set.end()) {
            result.push_back(item);
            res_set.insert(item);
        }
        generate(i+1,nums,result,item,res_set,sum,target);
        sum -= nums[i];
        item.pop_back();
        generate(i+1,nums,result,item,res_set,sum,target);
    }
};
    1. 括号生成

Java详细注释版本:

class Solution {
    
    private void generate(String item,int left,int right,List res) {
        //左括号和右括号满足上述条件的前提下都为n个,添加这个答案
        if(left == 0 && right == 0) {
            res.add(item);
            return;
        }
        //左括号的个数小于n 才能继续放左括号
        if(left > 0) {
            generate(item+"(",left-1,right,res);
        }
        //左括号个数必须大于右括号的放置个数 才能继续放右括号
        if(left < right) {
            generate(item+")",left,right-1,res);
        }
    }
    public List<String> generateParenthesis(int n) {
        /**
        *左括号个数必须大于右括号的放置个数 才能继续放右括号
        *左括号的个数小于n 才能继续放左括号
        *左括号和右括号满足上述条件的前提下都为n个,添加这个答案
        */
        List<String> res = new ArrayList<>();
        generate("",n,n,res);
        return res;
    }
}

cpp实现:

class Solution {
public:
    vector<string> generateParenthesis(int n) {
        vector<string> result;
        generate("",n,n,result);
        return result;
    }

private:
    void generate (string item, int left,int right,vector<string> &result) {
        if (left == 0 && right == 0) {
            result.push_back(item);
            return;
        }
        if (left > 0) {
            generate(item+'(',left - 1,right,result);
        }
        if (left < right) {
            generate(item + ')',left,right - 1,result);
        }
    }
};

写在最后

  1. 递归的思路若能理解即为手中很好的工具和武器,对付各类类暴力的枚举类题目有奇效。
  2. 重在理解递归本意,而不是单纯的做一道是一道。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

IMMUNIZE

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值