回溯算法-子集问题

子集

给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。

解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。

示例 1:

输入:nums = [1,2,3]
输出:[[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]

示例 2:

输入:nums = [0]
输出:[[],[0]]

提示:

  • 1 <= nums.length <= 10
  • -10 <= nums[i] <= 10
  • nums 中的所有元素 互不相同

分析

题目要求获得数组的所有可能的子集,需要穷举所有可能性,回溯算法是纯暴力搜索,回溯法是一种思想,通常采用递归法实现。

代码实现

class Solution {
public:
    vector<vector<int>> subsets(vector<int>& nums) {
        vector<vector<int> >res;
        vector<int>path;
        helper(res, nums, path, 0);
        return res;
    }
    void helper(vector<vector<int> >& res, vector<int>& nums, vector<int>& path, int start){
        res.push_back(path);
        for(int i = start; i < nums.size(); i++){
            path.push_back(nums[i]);
            helper(res, nums, path, i + 1);
            path.pop_back();
        }
    }
};

子集II

给你一个整数数组 nums ,其中可能包含重复元素,请你返回该数组所有可能的子集(幂集)。

解集 不能 包含重复的子集。返回的解集中,子集可以按 任意顺序 排列。

示例 1:

输入:nums = [1,2,2]
输出:[[],[1],[1,2],[1,2,2],[2],[2,2]]

示例 2:

输入:nums = [0]
输出:[[],[0]]

提示:

  • 1 <= nums.length <= 10
  • -10 <= nums[i] <= 10

分析:包含重复元素,如果前面已经选择过一个相同的数字了,选择该数时则跳过,如 [1, 2, 2 ],当path = [1], 此时选择最后的2加入时,因为前面已经出现过[ 1, 2 ],所以跳过选择。

          因为需要判断与上一个数字是否重复,并且子集可以按任意顺序排列,需要给nums数组排序。

代码实现:

class Solution {
public:
    vector<vector<int>> subsetsWithDup(vector<int>& nums) {
        vector<vector<int> > res;
        vector<int> path;
        sort(nums.begin(), nums.end());
        backtrack(nums, res, path, 0);
        return res;
    }
    void backtrack(vector<int>& nums, vector<vector<int> >& res, vector<int>& path, int idx){
        if(idx > nums.size()) return;
        res.push_back(path);
        for(int i = idx; i < nums.size(); i++){
            if(i != idx && nums[i] == nums[i - 1]) continue;
            path.push_back(nums[i]);
            backtrack(nums, res, path, i + 1);
            path.pop_back();
        }
    }
};

回溯算法模板

(组合问题,字符串切割问题,子集问题,排列问题,棋盘问题等)

res = []
path = []

def backtrack(未探索区域, res, path): #未探索区域一般借助下标索引实现
    if path 满足条件:
        res.add(path) # 深度拷贝
        return  # 如果不用继续搜索需要 return
    for 选择 in 未探索区域当前可能的选择:
        if 当前选择符合要求:
            path.add(当前选择)  #做选择
            backtrack(新的未探索区域, res, path)
            path.pop()   #撤销选择

选数

题目描述

已知 n 个整数 x1,x2,…,xn,以及1个整数k(k<n)。从n个整数中任选k个整数相加,可分别得到一系列的和。例如当n=4,k=3,4个整数分别为3,7,12,19时,可得全部的组合与它们的和为:

3+7+12=22

3+7+19=29

7+12+19=38

3+12+19=34

现在,要求你计算出和为素数共有多少种。

例如上例,只有一种的和为素数:3+7+19=29。

输入格式

键盘输入,格式为:

n,k(1≤n≤20,k<n)

x1​,x2​,…,xn​(1≤xi​≤5000000)

输出格式

屏幕输出,格式为: 1个整数(满足条件的种数)。

输入输出样例

输入

4 3
3 7 12 19

输出 

1
int nums[22];
int visited[22];
int res;
bool check(int N) {
	for (int i = 2; i < N; i++) {
		if (N % i == 0) return false;
	}
	return true;
}
void dfs(int start, int n, int k, vector<int>& path) {
	if (path.size() == k) {
		int sum = accumulate(path.begin(), path.end(), 0);
		if (check(sum)) res++;
	}
	for (int i = start; i <= n; i++) {
		if (!visited[i]) {
			path.push_back(nums[i]);
			visited[i] = 1;
			dfs(i, n, k, path);
			visited[i] = 0;
			path.pop_back();
		}
	}
}
int main() {
	int n, k;
	cin >> n >> k;
	for (int i = 1; i <= n; i++) {
		cin >> nums[i];
	}
	vector<int> path;
	dfs(1, n, k, path);
	cout << res;
	system("PAUSE");
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值