Description
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.
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]]
Solution 1
class Solution {
public:
void findcom(vector<vector<int>> &res, vector<int> cur, int helper[], int k, int n){
if(k==1){
if(n>0 && n<10 && helper[n-1]>0){
cur.push_back(n);
res.push_back(cur);
return;
}
} else {
for(int i=0; i<9; i++){
if(helper[i]>0 && helper[i]<n){
cur.push_back(helper[i]);
helper[i]=-helper[i];
findcom(res, cur, helper, k-1, n-1-i);
cur.pop_back();
}
}
}
}
vector<vector<int>> combinationSum3(int k, int n) {
int helper[9]={1,2,3,4,5,6,7,8,9};
vector<vector<int>> res;
vector<int> cur;
findcom(res, cur, helper, k, n);
return res;
}
};
Solution 2(C++)
class Solution {
public:
void findcom(vector<vector<int>> &res, vector<int> cur, vector<int> helper, int k, int n){
if(k==1){
if(n>0 && n<10 && helper[n-1]>0){
cur.push_back(n);
res.push_back(cur);
return;
}
} else {
for(int i=0; i<9; i++){
if(helper[i]>0 && helper[i]<n){
cur.push_back(helper[i]);
helper[i]=-helper[i];
findcom(res, cur, helper, k-1, n-1-i);
cur.pop_back();
}
}
}
}
vector<vector<int>> combinationSum3(int k, int n) {
vector<int> helper={1,2,3,4,5,6,7,8,9};
vector<vector<int>> res;
vector<int> cur;
findcom(res, cur, helper, k, n);
return res;
}
};
Solution 3(C++)
class Solution {
public:
vector<vector<int>> combinationSum3(int k, int n) {
vector<vector<int>> result;
vector<int> temp(k, 0);
int depth = 0;
int sum = 0;
while (depth >= 0) {
if (depth == k) {
if (sum == n) {
result.push_back(temp);
}
depth--;
continue;
}
if (depth > 0 && temp[depth] == 0) {
temp[depth] = temp[depth - 1] + 1;
sum += temp[depth];
} else {
temp[depth]++;
sum++;
}
if (temp[depth] == 10) {
sum -= temp[depth];
temp[depth] = 0;
depth--;
continue;
}
depth++;
}
return result;
}
};
算法分析
以上三个解法中,解法一与解法二中,解法一是错误的,解法二是正确的。其原因非常有意思。
首先比较重要的一点就是,我算是对值传递与引用传递有了新的理解了。对于值传递,其实就是在新的子函数体中开辟一块新的空间,用来存放值传递的值。那么函数结束之后,传递的参数其实是不会发生变化的。这一点非常适合回溯算法中的特点,那就是在每递归一次,相当于往深走一层,那么下一层的参数不会回传到上一层。每一层参数的变化只在本层变化。
所以基于此,对于需要全局改变的量,比如res,应该传递引用。对于每一层不同的量,比如,cur,k,n都应该传递值。当下一层函数执行完成之后,传递值的不会改变,只在下一层改变。此外,对于helper,解法一中是通过静态数组来储存的,但解法二中是通过vector< int >,解法一失败,但解法二成功。因为解法一虽然是传递形式为:int helper[],但其实这是将helper数组的名字,也就是指针传递,所以,helper还是会被修改。所以可以使用vector< int >
程序分析
略。