今天写代码的时候整体状态其实就不太好,整个人晕晕的,好多时候写出来的代码也是多少带点愚蠢。
93.复原IP地址
看卡哥说“大家做完 分割回文串 之后,本题就容易很多了”还以为是秒杀题呢,结果直接被卡住。怎么说呢,做完了分割回文串对这道题来说也只能大致想明白一个思路,但是具体实现上细节其实真的还蛮多的。
1 又忘记了分治思想
这个题我的代码再次把判断合法性和剪切的代码写到了一起,但这样想问题其实是会把问题复杂化的,用一个函数同时实现两个功能和用两个函数分别实现各自的功能并且组合起来,明显是后者要简单很多的。
2 循环终止条件没写对
写了个i < min(s.size(), 3);。怎么说呢,前面还知道是从startindex处开始的,后面就完全忘了这个事写了个3上去,那肯定就错了啊。
3 在修正完之后自信满满的改成了i < min(startindex + 3, s.size());,然而,又报错了,原因更是震碎三观,直接看GPT:
size()函数返回的竟然是一个叫size_t的无符号整型!
有一种这么多个题白写了的感觉:每当我写下一行int n = s.size();的时候,都发生了一次隐式转换,而我完全不知道,我只在乎我自己。
4 在排除0开头的时候,在循环外写了如下的代码:
if(s[startindex] == 0){
return;
}
这个代码会把每次遇到0的情况直接返回,不做任何输出。但这个逻辑是错的,因为当是一个单独的0的时候,其实是合法的!
除此之外,这还是一个char和int的判断,根本不可能相等。
作为改进,直接写成这样即可:
if (tocheck.size() > 1 && tocheck[0] == '0') break;
也就是直接把所有条件都列出来然后终止当前层的循环。
5 边界条件问题
一开始没有想的很清楚,有几个很容易混淆的点:
① for循环应该从i = startindex开始,还是i = startindex + 1开始?
自己想的是至少有一个元素所以从startindex+1开始,但如果是左闭右闭区间的话,右便捷其实取startindex就已经有一个元素在里面了,想岔了。
②substr是substr(startindex, i - startindex);,还是(startindex, i - startindex + 1);?
这个因为右边界是长度的原因,如果是左边的情况,在起始位置长度是0,那么其实代表空字符串,如果想要起始就有元素应该是+1才对的。
6 C++字符串转int又没长记性:
不是int(s),而是stoi(s)
最后修修改改写出了如下代码:
class Solution {
public:
vector<string> restoreIpAddresses(string s) {
int startindex = 0;
int time = 0;
vector<string> path;
vector<string> result;
split(s, startindex, time, path, result);
return result;
}
void split(string s, int startindex, int time, vector<string>& path, vector<string>& result) {
if(time == 4 && startindex == s.size()){
string ip;
for(int i = 0; i < path.size(); i++){
ip += path[i];
if(i != path.size()-1){
ip += ".";
}
}
result.push_back(ip);
}
else if(startindex == s.size() || time >= 4){
return;
}
// if(s[startindex] == '0'){
// return;
// }
for(int i = startindex; i < min(startindex + 3, int(s.size())); i++){
string tocheck = s.substr(startindex, i - startindex + 1);
if (tocheck.size() > 1 && tocheck[0] == '0') break;
if(stoi(tocheck) > 255){
break;
}
path.push_back(tocheck);
split(s, i+1, time+1, path, result);
path.pop_back();
}
}
};
但说一千道一万,其实大部分的麻烦都是试图将两个函数二合一所带来的问题。以后遇到一个比较麻烦的题,应该最先想到的是能不能分成几个不同的块去处理。
78.子集
本题整体没遇到什么问题,就是一个要注意的点:
空集也算子集,要添加进去即可。
class Solution {
public:
vector<vector<int>> subsets(vector<int>& nums) {
vector<vector<int>> result;
vector<int> path;
result.push_back(path);
int startindex = 0;
split(nums, startindex, result, path);
return result;
}
void split(vector<int>& nums, int startindex, vector<vector<int>>& result, vector<int>& path) {
if(startindex == nums.size()){
return;
}
for(int i = startindex; i < nums.size(); i++){
path.push_back(nums[i]);
result.push_back(path);
split(nums, i + 1, result, path);
path.pop_back();
}
}
};
90.子集II
本题一整个就是对之前代码的一个默写,索性我的记忆力还是不错的,但还是有一个地方默写错了:if (i > startindex && nums[i] == nums[i - 1]) continue;把if写成while了,结果就是发生无限循环。我还在纳闷哪里出问题了呢,属实犯蠢。
class Solution {
public:
vector<vector<int>> subsetsWithDup(vector<int>& nums) {
vector<vector<int>> result;
vector<int> path;
result.push_back(path);
sort(nums.begin(), nums.end());
int startindex = 0;
split(nums, startindex, result, path);
return result;
}
void split(vector<int>& nums, int startindex, vector<vector<int>>& result, vector<int>& path){
if(startindex >= nums.size()){
return;
}
for(int i= startindex; i < nums.size(); i++){
if(i > startindex && nums[i] == nums[i-1]){
continue;
}
path.push_back(nums[i]);
result.push_back(path);
split(nums, i+1, result, path);
path.pop_back();
}
}
};