给定一组不含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。
说明:解集不能包含重复的子集。
示例:
输入: nums = [1,2,3]
输出:
[
[3],
[1],
[2],
[1,2,3],
[1,3],
[2,3],
[1,2],
[]
]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/subsets
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路分析:
1:使用递归和回溯的思想解决
对nums从0到结束,分别把当前第nums[i]个元素放入item和不放入item,把当前item存为结果后分别递归该函数,求得子集。
void generate(int i,vector<int> &nums,vector<int> &item,vector<vector<int> > &result) { if(i >= nums.size()) { return; } item.push_back(nums[i]); result.push_back(item); generate(i+1,nums,item,result); item.pop_back(); generate(i+1,nums,item,result); } 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; } };
2:利用位运算和二进制保存结果
比如对集合ABCD求他的子集 把ABCD看成4位二进制数,每一位分别对应ABCD四个数,求其子集就是求所有4位二进制数所对应的集合。
class Solution { public: vector<vector<int> > subsets(vector<int>& nums) { vector<vector<int> > result; int all_set = 1 << nums.size();//2^n for(int i = 0; i < all_set; i++) { vector<int> item; for(int j = 0; j < nums.size(); j++) { if(i & (1 << j) )//1<<j代表当前nums数组的第j个元素如果和i相与为真就把它加入集合 { item.push_back(nums[j]); } } result.push_back(item); } return result; } };
90. 子集 II
给定一个可能包含重复元素的整数数组 nums,返回该数组所有可能的子集(幂集)。
说明:解集不能包含重复的子集。
示例:
输入: [1,2,2]
输出:
[
[2],
[1],
[1,2,2],
[2,2],
[1,2],
[]
]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/subsets-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
主要思路:这个题和上一个题类似 主要思路是先对数组进行排序,之后再递归所有子集的时候利用set的find功能去重。
void Generate(int i,vector<int> &nums, vector<int> &item,vector<vector<int> >&result,set<vector<int> > &reset) { if(i>= nums.size()) return; item.push_back(nums[i]); if(reset.find(item) == reset.end())//没有找见 { result.push_back(item); reset.insert(item); } Generate(i+1,nums,item,result,reset); item.pop_back(); Generate(i+1,nums,item,result,reset); } class Solution { public: vector<vector<int> > subsetsWithDup(vector<int>& nums) { sort(nums.begin(),nums.end()); vector<vector <int> > result; vector<int> item; set<vector<int> > reset; result.push_back(item); Generate(0,nums,item,result,reset); return result; } };
40. 组合总和 II
给定一个数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。
candidates 中的每个数字在每个组合中只能使用一次。
说明:
所有数字(包括目标数)都是正整数。
解集不能包含重复的组合。
示例 1:
输入: candidates = [10,1,2,7,6,1,5], target = 8,
所求解集为:
[
[1, 7],
[1, 2, 5],
[2, 6],
[1, 1, 6]
]
示例 2:
输入: candidates = [2,5,2,1,2], target = 5,
所求解集为:
[
[1,2,2],
[5]
]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/combination-sum-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
其实这个题也可以用位运算 不过输入太大 超时或超出限制……
class Solution { public: vector<vector<int>> combinationSum2(vector<int>& candidates, int target) { vector<vector<int> > result; set<vector<int> > reset; sort(candidates.begin(),candidates.end()); int all_set = 1 << candidates.size();//2^n for(int i = 0; i < all_set; i++) { vector<int> item; int sum = 0; for(int j = 0; j < candidates.size(); j++) { if(i & (1 << j) )//1<<j代表当前nums数组的第j个元素如果和i相与为真就把它加入集合 { item.push_back(candidates[j]); sum += candidates[j]; } } if((sum == target) && (reset.find(item)) == reset.end()) result.push_back(item); reset.insert(item); } return result; } };
还是看看有没有好方法,剪枝!比如选择的数字本身已经超过了target 就可以结束递归。同理 如果sum和超过了target也可以剪枝。
void Generate(int sum,int target,int i,vector<int> &nums, vector<int> &item,vector<vector<int> >&result,set<vector<int> > &reset) { if(i>= nums.size()) return; if(nums[i] > target) return; if(sum > target) return; item.push_back(nums[i]); sum+=nums[i]; if(sum == target && reset.find(item) == reset.end())//没有找见 { result.push_back(item); reset.insert(item); } Generate(sum,target,i+1,nums,item,result,reset); sum-=nums[i]; item.pop_back(); Generate(sum,target,i+1,nums,item,result,reset); } class Solution { public: vector<vector<int>> combinationSum2(vector<int>& nums, int target) { sort(nums.begin(),nums.end()); vector<vector <int> > result; vector<int> item; set<vector<int> > reset; Generate(0,target,0,nums,item,result,reset); return result; } };
22. 括号生成
给出 n 代表生成括号的对数,请你写出一个函数,使其能够生成所有可能的并且有效的括号组合。
例如,给出 n = 3,生成结果为:
[
"((()))",
"(()())",
"(())()",
"()(())",
"()()()"
]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/generate-parentheses
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
void Solve(int left,int right,string item,vector<string> &result) { if(left == 0 && right == 0) { result.push_back(item); return; } if(left > 0) { Solve(left-1,right,item+"(",result); } if(left< right) { Solve(left,right-1,item+")",result); } } class Solution { public: vector<string> generateParenthesis(int n) { vector<string> result; Solve(n,n,"",result); return result; } };
51. N皇后
n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。
上图为 8 皇后问题的一种解法。
给定一个整数 n,返回所有不同的 n 皇后问题的解决方案。
每一种解法包含一个明确的 n 皇后问题的棋子放置方案,该方案中 'Q' 和 '.' 分别代表了皇后和空位。
示例:
输入: 4
输出: [
[".Q..", // 解法 1
"...Q",
"Q...",
"..Q."],
["..Q.", // 解法 2
"Q...",
"...Q",
".Q.."]
]
解释: 4 皇后问题存在两个不同的解法。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/n-queens
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
void put_down(int x,int y,vector<vector<int> > &mark) { static int dx[] = {-1,0,1,-1,1,-1,0,1}; static int dy[] = {-1,-1,-1,0,0,1,1,1};//方向数组 mark[x][y] = 1;//放置皇后 for(int i = 1 ; i < mark.size();i++) { for(int j = 0; j < 8; j++) { int new_X = x + i * dx[j]; int new_Y = y + i * dy[j]; if(new_X < mark.size() && new_Y < mark.size() && new_X >= 0 && new_Y >= 0) { mark[new_X][new_Y] = 1; } } } } void Generate(int k, int n,vector<string> &location,vector<vector<string> >&result,vector<vector<int> >&mark)//正在放置第K个皇后 { if(n == k)//棋子放完的时候结束递归 { result.push_back(location); return; } for(int i=0 ;i < n; i++) { if(mark[k][i] == 0) { vector<vector<int> > remark = mark;//未放置前的结果 location[k][i] = 'Q';//放置后的结果 put_down(k,i,mark); Generate(k + 1,n,location,result,mark);//递归放置 mark = remark;//回溯回退 location[k][i] ='.'; } } } class Solution { public: vector<vector<string> > solveNQueens(int n) { vector<vector<string> > result; vector<string> location; vector<vector<int> > mark; for(int i = 0; i < n; i++) { mark.push_back(vector<int>()); for(int j = 0; j < n;j++) { mark[i].push_back(0); } location.push_back(""); location[i].append(n,'.'); } Generate(0,n,location,result,mark); return result; } };