前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >递归&回溯-子集之和

递归&回溯-子集之和

作者头像
BUPTrenyi
发布2019-07-15 16:58:58
5120
发布2019-07-15 16:58:58
举报
文章被收录于专栏:算法其实很好玩

一 唠嗑

今天有两篇文章!怎么样,惊不惊喜意不意外

今天这两道题昨晚,面试时候子集问题你被问住了,请来找我

二 上题!

面试官问完你上个题,你给出了,他说,那我改一下

Q:已知一个数组,可能有重复元素,给定值target,求出所有子集中,和为target的,不重复的子集。

举例:对于数组【10, 1, 2, 7, 6, 1, 5】,target = 8

则需要返回【【1,7】,【1,2,5】,【2,6】,【1,1,6】】

三 冷静分析

此时你脱口而出:这没区别啊,上道题代码原封不动,我算一下result的和是不是target,是的话,再追加进新数组,不就行了,这种题也拿来面我,渣渣

但你知道,这肯定不是他想要的答案,对吗

那能不能优化呢?

冷静分析:

这道题多了什么?target!

我们在递归&回溯过程中用到了吗?没有!

怎么用?

不卖关子,在深搜算法题中,用的非常广泛的思想-剪枝

当有额外条件时,如果不加以限制,那么将多出很多,不满足额外条件的搜索,没有意义。所以这时候我们要利用条件,在递归回溯时判断,进而决定走向再执行的过程,我们成为剪枝。

那么就很简单了,设置变量sum,当当前sum值>target时,比如10 > 8,根本不需要往下继续递归了,这就降低了时间复杂度,在数据量很大的情况下,剪枝的好处一目了然。

当然,记得回溯时,变量sum也要对应地减去当前元素。

四 完整代码及注释

代码语言:javascript
复制
//
// Created by renyi on 2019/6/26.
//
#include <iostream>
#include <set>
#include <vector>
#include <algorithm>
using namespace std;

void findSubsetsSum(int i, vector<int> &nums, vector<int> &item, vector<vector<int>> &result, set<vector<int>> &res_set, int sum, int target){
    if (i >= nums.size() || sum > target){//sum是当前item中元素的和,一旦大于了target,比如10 > 8,就不在递归回溯了,即,剪枝
        return;
    }

    sum += nums[i];//累加sum
    item.push_back(nums[i]);//追加进临时数组item

    if (res_set.find(item) == res_set.end() && sum == target){//item没在集合中,且sum==target,即找到了和是target的子集
        result.push_back(item);//追加结果和集合
        res_set.insert(item);
    }
    findSubsetsSum(i + 1, nums, item, result, res_set, sum, target);
    sum -= nums[i];//回溯时,sum要减去nums【i】并从item中删除nums【i】
    item.pop_back();
    findSubsetsSum(i + 1, nums, item, result, res_set, sum, target);
}

vector<vector<int>> subsets(vector<int> &nums, int target){
    vector<vector<int>> result;
    vector<int> item;
    set<vector<int>> res_set;
    sort(nums.begin(), nums.end());//和上道题一样,依然先排序
    findSubsetsSum(0, nums, item, result, res_set, 0, target);
    return result;
}

int main(){
    vector<int> nums;
    nums.push_back(10);
    nums.push_back(1);
    nums.push_back(2);
    nums.push_back(7);
    nums.push_back(6);
    nums.push_back(1);
    nums.push_back(5);
    vector<vector<int>> result;
    result = subsets(nums, 8);
    for (int i = 0; i < result.size(); i++) {
        if (result[i].size() == 0){
            printf("[]");
        }
        for (int j = 0; j < result[i].size(); j++) {
            printf("[%d]", result[i][j]);
        }
        printf("\n");
    }
    return 0;
}

结果

瞅啥瞅,没了,动动手码起来吧

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-06-26,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 算法其实很好玩 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档