leedcode-39 组合总和

给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。

candidates 中的数字可以无限制重复被选取。

说明:

所有数字(包括 target)都是正整数。
解集不能包含重复的组合。
示例 1:

输入: candidates = [2,3,6,7], target = 7,
所求解集为:
[
  [7],
  [2,2,3]
]

示例 2:

输入: candidates = [2,3,5], target = 8,
所求解集为:
[
  [2,2,2,2],
  [2,3,3],
  [3,5]
]

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/combination-sum
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

update 10:00
思路:
此题目是典型的动态规划思路,将复杂的问题拆解成若子问题,如此题目:
首先对condidates从小到大排序
循环开始
设要解决的是 func(candidates[i:],target)
循环过程
可以分解为 condidates[i] + func(candidates[i:],target-condidates[i]) | func(condidates[i+1:],target)
循环终止条件
i==len(condidates)-1 直接判断 target是否可以整除
i< len(condidates) 如果condidate[i] > target 终止查找,返回未找到,
效率优化
通常动态规划都可以使用空间来换时间,如这里可以保存 func(candidates[i:],target) 找到的序列,如果有其他的子问题也到这里,可以直接返回,不用再次进行分解:
按照此思路有代码:

class Solution {
public:
    vector<vector<int>> getCombin(vector<int>& c, int target,int index) {
       // printf("\r\n %d  %d\r\n",target,index);
        
        vector<vector<int>> ret;
        if (target < c[index])
            return ret;
        if (c.size() == index+1 || target == c[index]){
          if (target % c[index] == 0){
            vector<int> tmp;
            for(int i = 0 ; i < target / c[index] ;i++){
                tmp.push_back(c[index]);
            }
            ret.push_back(tmp);
          }
          return ret;
        } else{
            vector<vector<int>> net_result = getCombin(c,target-c[index],index);
                for(int i=0;i<net_result.size();i++){
                    net_result[i].insert(net_result[i].begin(),c[index]);
                }
            vector<vector<int>> net_result2 = getCombin(c,target,index+1);
           // printf("\r\n ----%d  %d\r\n",target,index);
            for (int i =0 ;i<net_result2.size();i++){
                net_result.push_back(net_result2[i]);
            }
            return net_result;
        }
    }
    vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
        sort(candidates.begin(),candidates.end());
        vector<vector<int>> ret;
        if (candidates.size() == 0)
            return ret;
        return getCombin(candidates,target,0);
    }
};

这里图简单,没有把空间换时间加上
在这里插入图片描述

现在我来吧空间换时间加上试试:

class Solution {
public:
    map<pair<int,int>,vector<vector<int> > > tmp_result; 
    vector<vector<int>> getCombin(vector<int>& c, int target,int index) {
        if (tmp_result.find({target,index}) != tmp_result.end()) {
            return tmp_result[{target,index}];
        }
        vector<vector<int>> ret;
        if (target < c[index]){
            tmp_result[{target,index}] = ret;
            return ret;
        }
        if (c.size() == index+1 || target == c[index]){
          if (target % c[index] == 0){
            vector<int> tmp;
            for(int i = 0 ; i < target / c[index] ;i++){
                tmp.push_back(c[index]);
            }
            ret.push_back(tmp);
          }
          tmp_result[{target,index}] = ret;
          return ret;
        } else{
            vector<vector<int>> net_result = getCombin(c,target-c[index],index);
                for(int i=0;i<net_result.size();i++){
                    net_result[i].insert(net_result[i].begin(),c[index]);
                }
            vector<vector<int>> net_result2 = getCombin(c,target,index+1);
           // printf("\r\n ----%d  %d\r\n",target,index);
            for (int i =0 ;i<net_result2.size();i++){
                net_result.push_back(net_result2[i]);
            }
            tmp_result[{target,index}] = net_result;
            return net_result;
        }
    }
    vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
        sort(candidates.begin(),candidates.end());
        vector<vector<int>> ret;
        if (candidates.size() == 0)
            return ret;
        return getCombin(candidates,target,0);
    }
};

在这里插入图片描述
提升不是很明显.
考虑到在递归调用返回时有大量的数组拷贝传递,可以进一步优化(这个是我看leedcode中其他人的评论得到的)

class Solution {
public:
    vector<vector<int>> vt; 
    vector<int> vx;
    void getsome(vector<int>& vis, int index, int cnt){
        if(cnt == 0){
            vt.push_back(vx);
            return ;
        }
        if(index >= vis.size() || cnt < 0)
            return ;
        if(vis[index] <= cnt){
            vx.push_back(vis[index]);
            getsome(vis, index, cnt-vis[index]);
            vx.pop_back();
        }
        getsome(vis, index+1, cnt);
    }
    vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
        if(candidates.empty()){
            return vt;
        }
        getsome(candidates, 0, target);
        return vt;
    }
};
  • 相比于我之前写的代码在返回参数时减少了一次vector的拷贝,所以节约了时间,这种做法最终的时间是
    在这里插入图片描述
    但这种做法递归间复用vx ,vt的全局变量, 无法写成多线程,而我之前的做法可以改成多线程从而加快速度.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值