DFS求组合的问题~

来源:互联网 发布:淘宝话费券怎么用 编辑:程序博客网 时间:2024/06/05 18:40


leetcode上面有很多类似的变形问题~这类问题的求解非常相似,一般用DFS递归求解~下面总结一下:
我们从全排列C(M,N)开始

1、

Combinations

 

Given two integers n and k, return all possible combinations of k numbers out of 1 ... n.

For example,
If n = 4 and k = 2, a solution is:

[  [2,4],  [3,4],  [2,3],  [1,2],  [1,3],  [1,4],]
明显用DFS解决,在(1-n)中一直递归选择下一个数 直到不能进行为止,当我们选择一个排列后,即size()==k,本次return,去掉上次选择的数,继续向下递归,(譬如我们刚开始选择12,size=2,去掉2,再从(3-4)中间选择,一直到不能继续为止),跟深度优先遍历树思路一致。C++代码如下:
void dfsCNKUique(vector<vector<int> > &v, vector<int> &mv, int n, int k, int start)  {  if (mv.size() == k)  {  v.push_back(mv);  return;  }  for (int i = start; i <= n; i++)  {  mv.push_back(i); dfsCNKUique(v, mv, n, k, i+1);  mv.pop_back();  }  } 


如果我们求A(m,n)该怎么求呢? 其实非常简单,只要修改一个变量即可
void dfsANKUique(vector<vector<int> > &v, vector<int> &mv, int n, int k, int start)  {  if (mv.size() == k)  {  v.push_back(mv);  return;  }  for (int i = start; i <= n; i++)  {  mv.push_back(i); dfsANKUique(v, mv, n, k, start+1);  mv.pop_back();  }  } 


再修改一个需求,我们要得到如下的结果:
如果输入n=4,k=2;结果如下:
  [4,4],  [3,4],  [3,3],  [2,4],  [2,2],  [2,3],  [1,1],  [1,2],  [1,3],  [1,4],
代码如下:
void dfsCNKNotUique(vector<vector<int> > &v, vector<int> &mv, int n, int k, int start)  {  if (mv.size() == k)  {  v.push_back(mv);  return;  }  for (int i = start; i <= n; i++)  {  mv.push_back(i); dfsCNKUique(v, mv, n, k, i);  mv.pop_back();  }  } 
同理,如果变形A(m,n)数可以重复,只需要将start+1变位start即可(此种情况会出现两个完全相同数重复的现象)。
下面来看一道变形的求和的组合的问题
2、

Combination Sum

 

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 (a1a2, … , 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] 

分析了问题1之后,这道问题就不是个事了,不就是求全排列C(1,N)...C(#,N)么,看是否与target相等。当然我们要注意,相同的数字可以连加,但是要保证不能有相同的组合,另外,全排列的上界#如何确定,他并不是单纯的N这么简单,假设numbers C中有一个数字为1,T为1000,那么存在一个组合1....1相加为1000,因此,上界确定也就呼之欲出了,首先我们需要对numbers C按非降序排序,这样,上界就是n=T/C[0]。
C++代码如下:
void dfsSumCombin(vector<vector<int> >& ret, vector<int>& vec, vector<int> &candidates, int target, int n, int sum,int cur) {if(sum > target)return;if(vec.size() == n) {if(sum == target) {ret.push_back(vec);}}for(int i = cur; i < candidates.size(); i++) {vec.push_back(candidates.at(i));dfsSumCombin(ret,vec,candidates,target,n,sum+candidates.at(i),i);vec.pop_back();}}

vector<vector<int> > combinationSum(vector<int> &candidates, int target) {vector<vector<int> > ret;int m = candidates.size();if(0==m)return ret;vector<int> vec;int n = target/candidates.at(0);for(int i = 1; i <= n; i++) {dfsSumCombin(ret,vec,candidates,target,i,0,0);}return ret;}


再看一道变形题,A了挺久的,囧~~~~~~~~~

3、Letter Combinations of a Phone Number

 

Given a digit string, return all possible letter combinations that the number could represent.

A mapping of digit to letters (just like on the telephone buttons) is given below.

Input:Digit string "23"Output: ["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"].

Note:
Although the above answer is in lexicographical order, your answer could be in any order you want.

题目意思很简单,跟上面几道题思路差不多,但是很多细节要注意,如果对递归了解不深的话,很难一遍AC。
刚好趁这道题熟悉了一下map的用法,递归代码简单易懂。但是卡了蛮久的,修为还是太浅。而且好几次bug,代码有点长,主要是用了map,并借助了一个两个vector程序显得不太简洁,如下代码:
 void dfs(vector<string>& vec,vector<string>& ret,string& s,int n, int cur) {        if(s.size() == n) {            vec.push_back(s);            return;        }        for(int i = 0; cur < ret.size() && i <ret.at(cur).size(); i++){//这里循环的是第cur个string里面的每个char,i由0开始            string temp = s;            temp+=ret.at(cur).at(i);            dfs(vec,ret,temp,n,cur+1);        }    }    vector<string> letterCombinations(string digits) {        vector<string> vec;        int n = digits.size();        map<char,string> mapdict;        initMaps(mapdict);//初始化map对象        vector<string> ret;        findAdaptMap(ret,mapdict,digits);//找到每个按下的数字键对应的string        string s;        dfs(vec,ret,s,n,0);        return vec;    }    void findAdaptMap(vector<string>& ret, map<char,string>& mapdict, string digits) {        int n = digits.size();        for(int i = 0; i < n; i++) {            char s = digits.at(i);            ret.push_back(mapdict[s]);        }    }        void initMaps(map<char,string>& mapdict) {        mapdict.insert(map<char,string>::value_type('2',"abc"));        mapdict.insert(map<char,string>::value_type('3',"def"));        mapdict.insert(map<char,string>::value_type('4',"ghi"));        mapdict.insert(map<char,string>::value_type('5',"jkl"));        mapdict.insert(map<char,string>::value_type('6',"mno"));        mapdict.insert(map<char,string>::value_type('7',"pqrs"));        mapdict.insert(map<char,string>::value_type('8',"tuv"));        mapdict.insert(map<char,string>::value_type('9',"wxyz"));    }


0 0
原创粉丝点击