深度优先搜索(DFS)它是一个搜索算法。第一次接触DFS它应该是一个二进制树的遍历内部,二叉树预订、序和后序实际上属于深度遍历-first。在本质上,深度优先搜索,遍历中则看到了更纯正的深度优先搜索算法。

通常。我们将回溯法和DFS等同看待。能够用一个等式表示它们的关系:回溯法=DFS+剪枝。所以回溯法是DFS的延伸。其目的在于通过剪枝使得在深度优先搜索过程中假设满足了回溯条件不必找到叶子节点。就截断这一条路径,从而加速DFS。

实际上,即使没有剪枝,DFS在从下层回退到上层的时候也是一个回溯的过程,通常这个时候某些变量的状态。

DFS通经常使用递归的形式实现比較直观。也能够用非递归。但通常须要借组辅助的数据结构(比方栈)来存储搜索路径。

以下通过leetcode上的两个题目,来展示DFS的应用:

题一  Combination Sum I,题目大意是这种:有一个正整数集合C,和一个目标数T(T也为正整数)。现从C中选出一些数,使其累加和恰好等于T(C中的每一个数都能够取若干次),求全部不同的取数方案。

比如:C={2,3,6,7}  T=7

res={  [7],

[2, 2, 3] }

class Solution {
public:
vector<vector<int> > combinationSum(vector<int> &candidates, int target) {
vector<int> tmp;
sort(candidates.begin(),candidates.end()); //先对C中候选数升序排序。为后面的剪枝做准备
sou=candidates;
dfs(tmp,target,0);
return res;
}
private:
vector<vector<int> > res; //保存最后结果
vector<int> sou;
int sum(vector<int> tmp){ //计算累加和
int r=0;
for(int i=0;i!=tmp.size();++i)
r+=tmp[i];
return r;
}
void dfs(vector<int> &tmp,int tag,int l){
if(l==sou.size()) //搜索到叶节点
return ;
int tot=sum(tmp);
if(tot==tag){
res.push_back(tmp);
return ;
}else if(tot>tag) //剪枝
return ;
else{
for(int i=l;i!=sou.size();++i){ //由于C中每一个数能够选多次,所以i从l開始,而不是l+1
tmp.push_back(sou[i]);
dfs(tmp,tag,i);
tmp.pop_back(); //回溯,恢复tmp状态
}
}
}
};

题二  Combination Sum II,与题一得差别是集合C中的每一个数最多仅仅能取一次,只是C中能够有反复的数。

比如:C={10,1,2,7,6,1,5}  T=8

res={ [1, 7]

                           [1, 2, 5]

                           [2, 6]

                           [1, 1, 6] }

题二能够採用与题一类似的方法。可是因为题二中的每一个数仅仅能取一次,所以dfs函数中的for循环,i应从l+1開始,表示取下一个数。但这样带来的问题是,结果中会出现反复的取数方案。拿上面的样例来分析:C中有两个1能够选,那第一个1和7是一种可选方案(1+7=8)。第二个1和7也是一种可选方案,依照上述算法。[1,7]会在结果中出现两次。当然能够对最后结果去重(假设用C++的话,sort->unique->erase能够实现)。

不幸的是,这样的解法会超时。解决超时的方案是不要将反复的方案增加到结果集中。也就避免了去重的工作。AC代码例如以下:

class Solution {
public:
vector<vector<int> > combinationSum2(vector<int> &candidates, int target) {
vector<int> tmp;
for(int i=0;i!=candidates.size();++i){ //mm是一个map,key为C中可取的数,value为该数有多少个
mm[candidates[i]]++;
}
for(map<int,int>::iterator it=mm.begin();it!=mm.end();++it){
for(int i=0;i<it->second;++i){
tmp.push_back(it->first);
dfs(tmp,target,it);
}
for(int i=0;i<it->second;++i){ //回溯。恢复tmp状态
tmp.pop_back();
}
}
return res;
}
private:
vector<vector<int> > res; //保存最后结果
map<int ,int > mm; int sum(vector<int> tmp){ //计算累加和
int r=0;
for(int i=0;i!=tmp.size();++i)
r+=tmp[i];
return r;
}
void dfs(vector<int> &tmp,int tag,map<int,int>::iterator it){
if(it==mm.end()) //搜索到叶节点
return ;
int tot=sum(tmp);
if(tot==tag){
res.push_back(tmp);
return ;
}else if(tot>tag) //剪枝
return ;
else{
for(++it;it!=mm.end();++it){
for(int i=0;i<it->second;++i){
tmp.push_back(it->first);
dfs(tmp,tag,it);
}
for(int i=0;i<it->second;++i){ //回溯,恢复tmp状态
tmp.pop_back();
}
}
}
}
};

关键代码:

for(++it;it!=mm.end();++it){
for(int i=0;i<it->second;++i){
tmp.push_back(it->first);
dfs(tmp,tag,it);
}
for(int i=0;i<it->second;++i){ //回溯,恢复tmp状态
tmp.pop_back();
}
}

外层循环表示依次从C中选取一种数。内层的第一个循环表示C中这个数能够取几次,内层的第二个循环表示,假设不选上一个数的话。要恢复状态。即把保存的上一个数删除(增加了多少个,就删除多少个)。

版权声明:本文博客原创文章。博客,未经同意,不得转载。

DFS-leetcode Combination Sum I/I I的更多相关文章

  1. 回溯法和DFS leetcode Combination Sum

    代码: 个人浅薄的认为DFS就是回溯法中的一种,一般想到用DFS我们脑中一般都有一颗解法树,然后去按照深度优先搜索去寻找解.而分支界限法则不算是回溯,无论其是采用队列形式的还是优先队列形式的分支界限法 ...

  2. [LeetCode]Combination Sum题解(DFS)

    Combination Sum Given a set of candidate numbers (C) (without duplicates) and a target number (T), f ...

  3. LeetCode Combination Sum III

    原题链接在这里:https://leetcode.com/problems/combination-sum-iii/ 题目: Find all possible combinations of k n ...

  4. LeetCode: Combination Sum I && II && III

    Title: https://leetcode.com/problems/combination-sum/ Given a set of candidate numbers (C) and a tar ...

  5. LeetCode: Combination Sum 解题报告

    Combination Sum Combination Sum Total Accepted: 25850 Total Submissions: 96391 My Submissions Questi ...

  6. [Leetcode] Combination Sum 系列

    Combination Sum 系列题解 题目来源:https://leetcode.com/problems/combination-sum/description/ Description Giv ...

  7. [LeetCode] Combination Sum IV 组合之和之四

    Given an integer array with all positive numbers and no duplicates, find the number of possible comb ...

  8. [LeetCode] Combination Sum III 组合之和之三

    Find all possible combinations of k numbers that add up to a number n, given that only numbers from ...

  9. [LeetCode] Combination Sum II 组合之和之二

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

  10. [LeetCode] Combination Sum 组合之和

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

随机推荐

  1. 【Jqurey EasyUI+Asp.net】---DataGrid增加、删、更改、搜

    在前面写了两,但不知道如何完成,对比刚刚开始学这个,他们摸着石头过河,一步步.在最后两天DataGridCRUD融合在一起.因此份额.我希望像我这样谁是刚刚开始学习一些帮助. 直接主题酒吧. 它是说数 ...

  2. android学习经常使用的数据文件夹

    android工程实践 1.仿360一键清理实现(一) "一键清理"是一个桌面图标,点击图标后,显示一个视图.进行清理动画.之后显示清理了几个进程,释放了多少M内存.点击" ...

  3. VS2013验证控件出现 WebForms UnobtrusiveValidationMode 必须“jquery”ScriptResour......错误的解决方案

    如下面的错误: 解决方式例如以下: 方法一: 在webconfig中找到 <appSettings> <addkey="aspnet:UseTaskFriendlySync ...

  4. ECG信号读出,检测QRS,P,T 波(小波去噪,并根据检测),基于BP辨识的神经网络

    这学期的课程选择神经网络.最后的作业处理ECG信号,并利用神经网络识别. 1  ECG引进和阅读ECG信号 1)ECG介绍  详细ECG背景应用就不介绍了,大家能够參考百度 谷歌.仅仅是简单说下ECG ...

  5. java.lang.ClassFormatError

    Error occurred during initialization of VMjava.lang.ClassFormatError: Unknown constant tag 26 in cla ...

  6. java编程接口(6) ------ 图标

    本文提出了自己的学习笔记,欢迎转载,但请注明出处:http://blog.csdn.net/jesson20121020 能够在JLable或者不论什么从AbstractButton继承的组件使用Ic ...

  7. 先学习Oracle 11g的Automatic Diagnostic Repository新功能

    Oracle 11g之前.当数据库出现故障,通常情况下,第一次需要看alert刊物.什么,看看哪些记录错误,您可以给我们的提示.alert文件名 是alert_<ORACLE_SID>.l ...

  8. Spark 1.0.0版本发布

    前言 如今Spark终于迈出了里程碑一步,1.0.0标记的版本号出版物Spark1.0时代.1.0.0版本号不仅增加了非常多新特性.而且提供了更好的API支持.Spark SQL作为一个新的组件增加. ...

  9. Java读取图像和网络存储

    该公司最近在搞一个Web工程,需要下载网络图片,那么既然恢复了一些最基本的东西.数据传输不同的流,简单,很容易下载网络打破了样品的图片,代码非常easy.贡献给大家! 结论,图片主要就四步: 1:拿到 ...

  10. 【SEO 决胜网络索引】 课程大纲及第一部分第一课:网络营销战略中的索引

    内容简介 1.课程大纲 2.第一部分第一课: 网络营销战略中的索引 3.第一部分第二课预告: 索引是什么 课程大纲 现在是网络为王的时代,人们越来越离不开互联网: SEO(Search Engine ...