77. 组合
这题做完之后还是有一种稀里糊涂的感觉。思考了半天什么范围合理,并且怎么设置才能让这个范围合理,然而一看答案,发现答案完全没考虑这些因素,直接暴力全遍历了。只能说确实这样能够放弃思考,比较省心一些...
class Solution {
public:vector<vector<int>> combine(int n, int k) {vector<vector<int>> result;vector<int> path;int startindex = 1;select(n, k, startindex, result, path);return result;}void select(int n, int k, int startindex, vector<vector<int>>& result, vector<int>& path){for(int i=startindex; i<=n; i++){path.push_back(i);if(path.size() == k){result.push_back(path);}else{select(n, k, i+1, result, path);}path.pop_back();}}
};
重新看了下剪枝操作的视频部分,其实当时就是没想清楚到底是多少,看完之后才知道是n-(k-patch.size())+1,这里面patch.size()表示已经添加的元素,k-patch.size()代表还需要添加的元素,那么,n-(k-patch.size())+1就表示要从这里开始的索引。
关于为什么要+1其实有一个比较好想的点,就是从a到(a+k)一共有k+1个元素,所以当我们需要k个元素的时候,最晚要从a+1开始。
216.组合总和III
在看完上题的解析后,本题我也是放弃了思考,但还是出现了两个小问题,都是因为没读题:
1 没看到要是k个数的和,以为是任意的
2 没看到只能是1-9,以为是任意的
class Solution {
public:vector<vector<int>> combinationSum3(int k, int n) {vector<vector<int>> result;vector<int> path;int startindex = 1;comb(k, n, startindex, result, path);return result;}void comb(int k, int n, int startindex, vector<vector<int>>& result, vector<int>& path) {if(n == 0 && path.size() == k){result.push_back(path);return ;}else if(n <0){return;}for(int i = startindex; i<=9; i++){path.push_back(i);n -= i;comb(k, n, i + 1, result, path);n += i;path.pop_back();}}
};
17.电话号码的字母组合
自己写了一段很蠢但是能执行的代码。
本来想的是用3*(电话按键-2)作为每段起点的,但是后来发现7和9还要做特殊处理,直接放弃了思考写出了如下代码。
class Solution {
public:vector<string> letterCombinations(string digits) {vector<string> s;string path;int i = 0;comb(digits, i, s, path);return s;}void comb(string digits, int curindex, vector<string>& s, string& path) {if(curindex == digits.size()){if(path != ""){s.push_back(path);}return ;}int now = digits[curindex]- '0';cout << now << endl;if(now == 2){for(int i = 0; i<3; i++){path += char('a' + i);comb(digits, curindex + 1, s, path);path.pop_back();}}else if(now == 3){for(int i = 0; i<3; i++){path += char('d' + i);comb(digits, curindex + 1, s, path);path.pop_back();}}else if(now == 4){for(int i = 0; i<3; i++){path += char('g' + i);comb(digits, curindex + 1, s, path);path.pop_back();}}else if(now == 5){for(int i = 0; i<3; i++){path += char('j' + i);comb(digits, curindex + 1, s, path);path.pop_back();}}else if(now == 6){for(int i = 0; i<3; i++){path += char('m' + i);comb(digits, curindex + 1, s, path);path.pop_back();}}else if(now == 7){for(int i = 0; i<4; i++){path += char('p' + i);comb(digits, curindex + 1, s, path);path.pop_back();}}else if(now == 8){for(int i = 0; i<3; i++){path += char('t' + i);comb(digits, curindex + 1, s, path);path.pop_back();}}else{for(int i = 0; i<4; i++){path += char('w' + i);comb(digits, curindex + 1, s, path);path.pop_back();}}}
};
在看完了卡哥的解析之后发现,二维数组确实是一个很好的存储方式,学到了。
用二维数组的话,就能避免像我的代码里一样不停地加加减减,只要正常用for循环遍历就行,更简单一点。
除此之外,还遇到了几个问题:
1 一开始判断条件写成了if(curindex == digits.size() - 1),然后报了一个栈溢出。这个为什么会导致栈溢出呢?当size是0的时候,等式右边是-1,但这个条件永远也达不到,因为curindex是永远不可能变成-1的,这就使得程序无线递归,直到发生栈溢出。
2 int now = digits[curindex] - '0';最开始没写后面的- '0';,导致实际上now的范围是从50开始的。实际上这里相当于是ascii码,需要减掉'0'对应的ascii码才是对的。
不过还有一个需要注意的一点,我修改的时候尝试了int(digits[curindex]),也不行,也输出的是ascii码。为什么不行呢?请看GPT:
也就是说实际上这个函数返回的也是ascii码。
3 不知道string怎么移除队尾元素,所以写了path -= char('j' + i);,但实际上string只重载了加号没有重载减号,所以这么写是会导致报错的。或者直接按照卡哥的写法,传参的时候这么传:
self.getCombinations(digits, index + 1, s + letter, result)
这样子的话,就不用考虑怎么减去了,因为本来就没加进去。