一般回溯搜索的题目在面试中容易出现,这类题目往往难度偏大。
78. Subsets
Medium
Given a set of distinct integers, nums, return all possible subsets (the power set).
Note: The solution set must not contain duplicate subsets.
Example:
Input: nums = [1,2,3] Output: [ [3], [1], [2], [1,2,3], [1,3], [2,3], [1,2], [] ]
这个题目的关键是每个元素只有选和不选两种状态,所以用递归回溯的办法很容易解决。
这里引函数以及三个辅助变量, 二维数组res用来储存最后的答案,temp数组用来记录每一组子集,start表示递归到状态数,这里要注意的是,递归的时候start填的是i+1, 表示从当前元素后面递归入了辅助。
class Solution {
vector<vector<int>> res;
void dfs(int start, vector<int> &nums,vector<int> &temp){
res.push_back(temp);
for(int i=start;i<nums.size();i++){
temp.push_back(nums[i]);
dfs(i+1,nums,temp);
temp.pop_back();
}
}
public:
vector<vector<int>> subsets(vector<int>& nums) {
vector<int> temp;
dfs(0,nums,temp);
return res;
}
};
递归树如下面所示,这里略去了所有不选的结果。
90. Subsets II
Medium
Given a collection of integers that might contain duplicates, nums, return all possible subsets (the power set).
Note: The solution set must not contain duplicate subsets.
Example:
Input: [1,2,2] Output: [ [2], [1], [1,2,2], [2,2], [1,2], [] ]
这里最直接的做法就是排序后简枝
注意这里剪枝的条件是i>start, 不是i>0,这样才具有普适性,同时不会溢出。
class Solution {
public:
vector<vector<int>> res;
vector<vector<int>> subsetsWithDup(vector<int>& nums) {
sort(nums.begin(),nums.end());
vector<int> temp;
dfs(nums,temp,0);
return res;
}
void dfs(vector<int>& nums, vector<int> temp, int start){
res.push_back(temp);
for(int i=start;i<nums.size();i++){
if(i!=start&& nums[i]==nums[i-1]) continue;
temp.push_back(nums[i]);
dfs(nums,temp,i+1);
temp.pop_back();
}
}
};
46. Permutations
Medium
Given a collection of distinct integers, return all possible permutations.
Example:
Input: [1,2,3] Output: [ [1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], [3,2,1] ]
这里的递归思路很巧妙,是先用1 [ 2,3], 2 [ 1, 3], 3[1,2], 有一个循环加上回溯
class Solution {
private:
vector<vector<int>> res;
void dfs(vector<int>& nums,int start){
if(start==nums.size()){
res.push_back(nums);
}
for(int i=start;i<nums.size();i++){
swap(nums[start],nums[i]);
dfs(nums,start+1);
swap(nums[start],nums[i]);
}
}
public:
vector<vector<int>> permute(vector<int>& nums) {
dfs(nums,0);
return res;
}
};
如果考虑到重复又要考虑剪枝问题
经过探索,这里剪枝不是仅仅考虑nums[start]==nums[i] continue, 而是从[start,i) 如果有等于nums[i]的这一个就跳过。
class Solution {
public:
vector<vector<int>> res;
vector<vector<int>> permuteUnique(vector<int>& nums) {
dfs(nums,0);
return res;
}
void dfs(vector<int>& nums, int start){
if(start==nums.size()){
res.push_back(nums);
}
for(int i=start;i<nums.size();i++){
bool flag = false;
for(int j=start;j<i;j++){
if(nums[j]==nums[i]){
flag = true;
}
}
if(flag) continue;
swap(nums[start],nums[i]);
dfs(nums,start+1);
swap(nums[start],nums[i]);
}
}
};