问题等价于:对每个字符进行计算,求得至少出现三次的单字符串的最大长度。
解题思路:对于每个字符,首先遍历,收集连续出现的字符的长度集合。
二分法
求得最大长度mid使得在其长度集合里能出现>=3次,长度k的集合里,能够贡献长度mid的个数是max(0,k-mid+1)。当k=mid时,代表只能贡献一个长度为K的子串。
for (int i = 0; i < 26; ++i) {
if (arr[i].empty())
continue;
int l = 1, r = s.size() - 2; // 分别表示最大和最小的长度
while (l <= r) { // !!要等号
int mid = (l + r) >> 1; // 搜索长度
int count = 0;
for (auto& k : arr[i]) {
// 遍历一个字符的所有长度子集
count += max(0, k - mid + 1);
// 计算每个子集能够凑出长度为mid的子串个数
}
if (count >= 3) {
// 满足条件
res = max(res, mid);
l = mid + 1;
} else {
r = mid - 1;
}
}
}
排序法
将一个字符的长度集合降序排序,只取前3就能计算结果。
只有三种情况:
1.最大的长度a[0]提供:3个长度为a[0]-2,满足题意
2.由a[0],a[1]提供。a[0]=a[1]时,最大长度是a[0]-1;a[0]>a[1]时,是a[1]。他们是取最小的关系!
3.最少有三个长度,那就能至少提供3个长度为a[2]的
for (int i = 0; i < 26; ++i) {
if (arr[i].empty())
continue;
sort(arr[i].begin(), arr[i].end(), greater<int>());
arr[i].push_back(0);
arr[i].push_back(0);
int t =
max({arr[i][0] - 2, min(arr[i][0] - 1, arr[i][1]), arr[i][2]});
res = max(t, res);
}