1 回溯法(first索引+剪枝)
本题讲真,略有麻烦,倒不是需要复杂的方法,而是根据题目要求需要多个判断才能保证AC,需要判断的条件如下
- 只能分成4段
- 每段数字个数
∈[1, 3]
- 每段数字个数多于
1
个时首个数字不能是0
- 每段数字个数为
3
时不能大于255
- 标点符号处理
class Solution {
public:
string path;
vector<string> res;
bool vaild(string& s) {
int size = s.size();
if (size > 3) return false;
if (s[0] == '0' && size > 1) return false;
int a = 0;
for (int i = 0; i < size; i++)
a += (s[i] - '0') * pow(10, size - 1 - i);
if (a > 255) return false;
return true;
}
void backtrack(string& s, int first, int len) {
if (s.size() == path.size() - 3 && len == 4) {
res.emplace_back(path);
return;
}
if (len > 4) return;
for (int i = first; i < first + 3 && i < s.size(); i++) {
string substr = s.substr(first, i - first + 1);
if (!vaild(substr)) continue;
if (len <= 2) substr += '.';
path += substr;
backtrack(s, i + 1, len + 1);
path = path.substr(0, path.size() - substr.size());
}
}
vector<string> restoreIpAddresses(string s) {
backtrack(s, 0, 0);
return res;
}
};
class Solution {
private:
int size;
vector<string> solution;
string path;
const int UNIT_LEN = 3; // 每段最长UNIT_LEN
const int SEG_LEN = 4; // 分成SEG_LEN个段
public:
bool notValid(string& str) {
// 3.每段数字个数多于1个时首个数字不能是0
if (str.size() > 1 && str[0] == '0') return true;
// 4.每段数字个数为3时不能大于255
if (str.size() == UNIT_LEN && str > "255") return true;
return false;
}
void backtrack(string& str, int first, int len) {
if (first == size && len == SEG_LEN) {
solution.emplace_back(path);
return;
}
// 1.只能分成4段
if (len > SEG_LEN) return;
// 2.每段数字个数∈[1, 3](段外右分支收紧)
if (UNIT_LEN * (SEG_LEN - len) < size - first) return;
// 2.每段数字个数∈[1, 3](段内右分支收紧)
for (int i = first; i < size && i < first + UNIT_LEN; i++) {
string subStr = str.substr(first, i - first + 1);
if (notValid(subStr)) continue;
subStr = path.empty() ? subStr : '.' + subStr; // 标点符号处理
path += subStr;
backtrack(str, i + 1, len + 1);
path = path.substr(0, path.size() - subStr.size());
}
}
vector<string> restoreIpAddresses(string s) {
size = s.size();
backtrack(s, 0, 0);
return solution;
}
};