KID_XiaoYuan

导航

回溯-递归练习题集

给定一组不含重复元素的整数数组 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;
    }
};
View Code

还是看看有没有好方法,剪枝!比如选择的数字本身已经超过了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;
    }
};

 

posted on 2020-02-09 19:03  KID_XiaoYuan  阅读(167)  评论(0编辑  收藏  举报