Leetcode Combination系列:39 & 77 & 40 & 216 & 17
39. Combination Sum:
问题描述:
Given a set of candidate numbers (candidates
) (without duplicates) and a target number (target
), find all unique combinations in candidates
where the candidate numbers sums to target
.
The same repeated number may be chosen from candidates
unlimited number of times.
Note:
- All numbers (including
target
) will be positive integers. - The solution set must not contain duplicate combinations.
Example 1:
Input: candidates =[2,3,6,7],
target =7
, A solution set is: [ [7], [2,2,3] ]
Example 2:
Input: candidates = [2,3,5],
target = 8,
A solution set is:
[
[2,2,2,2],
[2,3,3],
[3,5]
]
思路:
给出一组候选数字和一个目标数字, 要求返回能够组成目标数字的候选数字的组合,使用个数没有限制但是组合不能够重复。
我们可以使用DFS来解决这个问题。
为了更好的剪枝:我们可以对候选数组进行排序:由小到大的顺序。
从候选数组第一个该开始尝试:能否由含有该数字的组合构成一个和为目标数组的组合,因为对数字使用个数没有限制,我们在下一层递归中也应该从该数字开始寻找。如果target-candidates[i] < 0说明该数字与之前的数字的组合的和大于target,又因为我们对候选数组进行了排序,所以后面的较大的数字加入也一定大于目标数字,所以可以直接break。
代码:
class Solution { public: void combinationDFS(vector<vector<int>>& ret, int target, vector<int> &candidates, vector<int> comb, int start){ if(target == 0){ ret.push_back(comb); return; } for(int i = start; i < candidates.size(); i++){ if(target - candidates[i] < 0) return; int newT = target - candidates[i]; comb.push_back(candidates[i]); combinationDFS(ret, newT, candidates, comb, i); comb.pop_back(); } } vector<vector<int>> combinationSum(vector<int>& candidates, int target) { sort(candidates.begin(), candidates.end()); vector<vector<int>> ret; vector<int> comb; combinationDFS(ret, target, candidates, comb, 0); return ret; } };
-----------------------下一道题分割线---------------------------------------
77. Combinations
问题描述:
Given two integers n and k, return all possible combinations of k numbers out of 1 ... n.
Example:
Input: n = 4, k = 2 Output: [ [2,4], [3,4], [2,3], [1,2], [1,3], [1,4], ]
解题思路:
给出两个整数 n 和 k, 要给出所有由 k 个 [1,n] 中的数字组成的组合。
仔细观察给出的例子中,我发现了几个额外的要求:数字不能够重复利用如1,1就不在回答中。
并且没有重复的组合。
依然适用DFS来进行搜索。
代码:
class Solution { public: void FindComb(vector<vector<int>>& ret, vector<int>& comb, int k, int n, int start){ if(k == 0){ ret.push_back(comb); return; } for(int i = start; i <= n; i++){ comb.push_back(i); FindComb(ret, comb, k-1, n, i+1); comb.pop_back(); } } vector<vector<int>> combine(int n, int k) { vector<vector<int>> ret; if(k > n) return ret; vector<int> comb; FindComb(ret, comb, k, n, 1); return ret; } };
-----------------------------------我是下一题分割线--------------------------------------------
40. Combination Sum II
问题描述:
Given a collection of candidate numbers (candidates
) and a target number (target
), find all unique combinations in candidates
where the candidate numbers sums to target
.
Each number in candidates
may only be used once in the combination.
Note:
- All numbers (including
target
) will be positive integers. - The solution set must not contain duplicate combinations.
Example 1:
Input: candidates =[10,1,2,7,6,1,5]
, target =8
, A solution set is: [ [1, 7], [1, 2, 5], [2, 6], [1, 1, 6] ]
Example 2:
Input: candidates = [2,5,2,1,2], target = 5, A solution set is: [ [1,2,2], [5] ]
解题思路:
这道题与39的不同之处为给出的备选数组中可能存在重复的数字。
如果不加处理,一定会出现重复的组合:如当寻找完1开头的数字的时候,若有不止一个1出现,则一定再寻找一遍1开头的组合。
为了解决这种问题,我加了一个if语句来限定:判定条件为:( i-1 >= 0 && candidates[i-1] == candidates[i] )
但是执行后发现,加了这个判定语句后,并不能成功的利用备选数组中重复的数字,也就是在递归过程中依然会跳过。
而我们想做的是跳过同一层循环内的,不跳过递归里的。
所以我又多加了一个限定:
if(i-1 >= 0 && candidates[i-1] == candidates[i] && i > start)
当然这种成功的前提是我们对候选数组进行了排序。
代码:
class Solution { public: void findComb(vector<vector<int>> &ret, vector<int>& candidates, vector<int> &comb, int target, int start){ if(target == 0){ ret.push_back(comb); return; } for(int i = start; i < candidates.size(); i++){ if(i-1 >= 0 && candidates[i-1] == candidates[i] && i > start) continue; if(target - candidates[i] < 0) return; comb.push_back(candidates[i]); findComb(ret, candidates, comb, target - candidates[i], i+1); comb.pop_back(); } } vector<vector<int>> combinationSum2(vector<int>& candidates, int target) { sort(candidates.begin(), candidates.end()); vector<vector<int>> ret; vector<int> comb; findComb(ret, candidates, comb, target, 0); return ret; } };
----------------------------我是下一道题分割线---------------------------------------
216. Combination III
问题描述:
Find all possible combinations of k numbers that add up to a number n, given that only numbers from 1 to 9 can be used and each combination should be a unique set of numbers.
Note:
- All numbers will be positive integers.
- The solution set must not contain duplicate combinations.
Example 1:
Input: k = 3, n = 7 Output: [[1,2,4]]
Example 2:
Input: k = 3, n = 9 Output: [[1,2,6], [1,3,5], [2,3,4]]
解题思路:
感觉跟之前的没有什么差别,注意的是,从给出的例子来看,不允许组合中存在重复数字。
代码:
class Solution { public: void findComb(vector<vector<int>> &ret, vector<int> &comb, int k, int target, int start){ if(k == 0){ if(target == 0){ ret.push_back(comb); } return; } for(int i = start; i < 10; i++){ if(target - i < 0) return; comb.push_back(i); findComb(ret, comb, k-1, target-i, i + 1); comb.pop_back(); } } vector<vector<int>> combinationSum3(int k, int n) { vector<vector<int>> ret; vector<int> comb; findComb(ret, comb, k, n, 1); return ret; } };
-------------------------------------我是下一道题分割线----------------------------------
17. Letter combinations of Phone number
问题描述:
Given a string containing digits from 2-9
inclusive, 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. Note that 1 does not map to any letters.
Example:
Input: "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.
解题思路:
这道题多了一个小环节:就是建立数字到字母的映射,我们可以用map来实现。
其他的就差不多啦~
代码:
class Solution { public: void findComb(string digits, int idx, vector<string> &ret, string &comb, map<int,string> &letterM){ if(idx == digits.size()){ ret.push_back(comb); } string letters = letterM[digits[idx] - '0']; for(int i = 0; i < letters.size(); i++){ comb.push_back(letters[i]); findComb(digits, idx+1, ret, comb, letterM); comb.pop_back(); } } vector<string> letterCombinations(string digits) { vector<string> ret; if(digits.size() == 0) return ret; map<int, string> letter_map; letter_map[2] = "abc"; letter_map[3] = "def"; letter_map[4] = "ghi"; letter_map[5] = "jkl"; letter_map[6] = "mno"; letter_map[7] = "pqrs"; letter_map[8] = "tuv"; letter_map[9] = "wxyz"; string comb; findComb(digits, 0, ret, comb, letter_map); return ret; } };