题目
-
- 子集
2. 90. 子集 II
3. 40. 组合总和 II
4. 22. 括号生成
思路与算法
-
- 子集:注释的很详细,递归生成子集。还有一种位运算的方法更加简洁,但是如果不熟练的话会比较吃力。
-
- 子集 II: 其余思路同上题,总体不同在于通过排序去除乱序相同的子集,再通过set去重即可。
-
- 组合总和 II:还是在上一题的基础上,继续增加条件,在递归获取所有子集的同时,利用题目要求的target进行剪枝。
-
- 括号生成:也是此类递归代码的同类思路,重在理解这个过程。发现很久之前提交的Java版本注释的比较详细,cpp的也附上
代码实现
-
- 子集
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);
}
};
-
- 子集 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);
}
};
-
- 组合总和 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);
}
};
-
- 括号生成
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);
}
}
};
写在最后
- 递归的思路若能理解即为手中很好的工具和武器,对付各类类暴力的枚举类题目有奇效。
- 重在理解递归本意,而不是单纯的做一道是一道。