题目:

Given a set of candidate numbers (C) and a target number (T), find all unique combinations in C where the candidate numbers sums to T.

The same repeated number may be chosen from C unlimited number of times.

Note:

  • All numbers (including target) will be positive integers.
  • Elements in a combination (a1, a2, … , ak) must be in non-descending order. (ie, a1 ≤ a2 ≤ … ≤ ak).
  • The solution set must not contain duplicate combinations.

For example, given candidate set 2,3,6,7 and target 7, 
A solution set is: 
[7] 
[2, 2, 3]

题目的意思是给定一个candidate集合,里面包含一些数字,给定一个目标T,在集合中找出可以组合成T的所有组合,集合中的数字可以重复利用。但组合后的结果不能重复。结果中按非降序排列。举例集合C为 2,3,6,7 目标位7,那么就有两种组合满足,一个是[2,2, 3] 一个是[7]

思路:

利用回溯法,深度优先。剪枝判断是相加的数大于目标时返回,或者相加之和为目标的时候记录在ans中并返回。如果相加小于目标,那就往下一层找,找到满足要返回的条件为止。

class Solution {
public:
int sum38(vector<int> vec) // 返回vec中所有值的和,用来和target判断用
{
if (vec.size() == 0)
return -1;
int len = vec.size(), ans = 0;
for (int i = 0; i < len; ++i)
{
ans += vec[i];
}
return ans;
}
void back38(vector<vector<int> > &ans, vector<int> &candidates, vector<int> &tmp, int target, int cur)
{
for (int i = cur; i < candidates.size(); ++i) // i从传入的cur下标开始,cur初始为0,之后根据i改变,为了保证不会有重复解
{
int num = sum38(tmp); // 避免三个if语句都调用sum38,计算一次就好,否则超时
if (num == target)
{
ans.push_back(tmp); // 如果找到了一组,就记录后返回
return;
}
if (num < target) // 如果比目标还小,说明还要在加一个数
{
tmp.push_back(candidates[i]);
back38(ans, candidates, tmp, target, i); // tmp加了一个数后再递归,注意此处传入的cur为i,这样为了保证不会有重复的解
// 因为candidates是排好序的,所以之后递归中要加的数只能是下标i之后的
tmp.pop_back(); // 递归返回到这可定是之前相等或者是大于了,所以要去掉tmp的最后一个,再继续找
}
if (num > target)
{
return;
}
}
}
vector<vector<int> > combinationSum(vector<int> &candidates, int target)
{
std::sort(candidates.begin(), candidates.end()); // 因为给的数不是有序的,所以一定要先排好序,才能为之后避免重复解
vector<vector<int> > ans;
vector<int> tmp;
back38(ans, candidates, tmp, target, 0);
return ans;
}
};

这个在oj上要440ms。发现时间主要是用在计算vec的和上了。在网上看别人的做法,发现还有个巧妙的技巧。就是传入的target每次变小,知道为零是即为满足条件。剪枝判断是用target和当前想要加入的元素进行比较,如果target比较大那就把target减去要加入的元素之后的值当做下一次的target。同理如果要加入的值都比当前的target更大了就可以剪枝返回了。

这个代码只要80ms,提高了5倍

void back38(vector<vector<int> > &ans, vector<int> &candidates, vector<int> &tmp, int target, int cur)
{
for (int i = cur; i < candidates.size(); ++i)
{
if (0 == target) // 为零即之前的组合满足最初target
{
ans.push_back(tmp);
return;
}
if (candidates[i] <= target) // 如果将要加入的不比目标大,加入
{
tmp.push_back(candidates[i]);
back38(ans, candidates, tmp, target - candidates[i], i);
tmp.pop_back();
}
if (candidates[i] > target) // 剪枝
{
return;
}
}
}

leetcode第38题--Combination Sum的更多相关文章

  1. leetcode第39题--Combination Sum II

    题目: Given a collection of candidate numbers (C) and a target number (T), find all unique combination ...

  2. Leetcode 39 40 216 Combination Sum I II III

    Combination Sum Given a set of candidate numbers (C) and a target number (T), find all unique combin ...

  3. LeetCode(40) Combination Sum II

    题目 Given a collection of candidate numbers (C) and a target number (T), find all unique combinations ...

  4. LeetCode笔记:39. Combination Sum

    题目描述 给定一个无重复的正整数数组 candidates 和一个正整数 target, 求所有和为 target 的 candidates 中数的组合中.其中相同数的不同顺序组合算做同一种组合,ca ...

  5. LeetCode(39) Combination Sum

    题目 Given a set of candidate numbers (C) and a target number (T), find all unique combinations in C w ...

  6. leetcode第38题:报数

    这是一道简单题,但是我做了很久,主要难度在读题和理解题上. 思路:给定一个数字,返回这个数字报数数列.我们可以通过从1开始,不断扩展到n的数列.数列的值为前一个数列的count+num,所以我们不断叠 ...

  7. leetcode个人题解——#39 Combination Sum

    思路:先对数据进行排序(看评论给的测试数据好像都是有序数组了,但题目里没有给出这个条件),然后回溯加剪枝即可. class Solution { public: ; vector<vector& ...

  8. LeetCode:40. Combination Sum II(Medium)

    1. 原题链接 https://leetcode.com/problems/combination-sum-ii/description/ 2. 题目要求 给定一个整型数组candidates[ ]和 ...

  9. Leetcode 之 Combination Sum系列

    39. Combination Sum 1.Problem Find all possible combinations of k numbers that add up to a number n, ...

随机推荐

  1. 王立平--Button底,点击效果设置

    1.新....xml <? xml version="1.0" encoding="utf-8"?>        <selector xml ...

  2. C# DateTime结构的常用方法

    在项目开发中,经常会碰到日期处理.比如查询中,可能会经常遇到按时间段查询,有时会默认取出一个月的数据.当我们提交数据时,会需要记录当前日期,等等.下面就看看一些常用的方法. 首先,DateTime是一 ...

  3. Java设计模式菜鸟系列(十三)建模和实现状态模式

    转载请注明出处:http://blog.csdn.net/lhy_ycu/article/details/39829859 状态模式(State):同意对象在内部状态改变时改变它的行为,对象看起来好像 ...

  4. 使用方便git命令检查记录的版本号

    现在开始git大多数用户都经历过subversion,对于这两种开关的版本控制系统需要一段时间去适应.本文旨在帮助恢复一些,这些用户都熟悉的日志记录买家的习惯. 我们要熟悉一个详细的例子git中log ...

  5. SpringMVC注释启用

    这篇文章是我学习的网络视频SpringMVC写的过程. 谢谢公布各位前辈的视频 以下评论SpringMVC几个关键步骤,注意事项启用: 首先需要加载配置文件(假设请使用自定义路径) <? xml ...

  6. krpano漫游加方向性3D声音(这篇文章已被移到krpano中国网站 krpano360.com)

    需求:      在场景转换视角时.会出现不同方位的声音以及对应的音量变化,也即是将声音视作hotspot.当视角转到该声音热点时,也随之听到声音.官方样例:点击打开链接 本文已经搬迁到下述网址.请点 ...

  7. hdu2844 &amp; poj1742 Coin ---多重背包--两种方法

    意甲冠军:你有N种硬币,每个价格值A[i],每个号码C[i],要求. 在不超过M如果是,我们用这些硬币,有多少种付款的情况下,.那是,:1,2,3,4,5,....,M这么多的情况下,,你可以用你的硬 ...

  8. android浏览器开发小技巧集锦(转)

    本人和朋友们做了一段时间浏览器,将一些小技巧分享出来,先写一部分,慢慢写,同时也为我们的浏览器打打广告 我们的浏览器将要上线,名叫沙发浏览 1.网页内的右键菜单 public boolean onLo ...

  9. XStream 用法汇总

            XStream是一家Java对象和XML转换工具,很好很强大.它提供了所有的基本型.排列.收集和其他类型的支持,直接转换.因此XML在数据交换经常使用.对象序列化(和Java对象的序列 ...

  10. 《Javascript权威指南》十六学习笔记:BOM资源---BOM基本应用

    BOM基本应用包括:管理浏览器历史记录.得到处理和解决浏览器的信息.本文介绍了这些应用程序. 一.浏览历史管理 1.history对象的方法和属性 History 对象包括用户(在浏览器窗体中)訪问过 ...