题目(中等)
如果字符串中的所有字符都相同,那么这个字符串是单字符重复的字符串。
给你一个字符串 text,你只能交换其中两个字符一次或者什么都不做,然后得到一些单字符重复的子串。返回其中最长的子串的长度。
示例 1:
输入:text = “ababa”
输出:3
示例 2:
输入:text = “aaabaaa”
输出:6
示例 3:
输入:text = “aaabbaaa”
输出:4
示例 4:
输入:text = “aaaaa”
输出:5
示例 5:
输入:text = “abcdef”
输出:1
提示:
1 <= text.length <= 20000
text 仅由小写英文字母组成。
解题思路
分割字符串+分类讨论
首先将整个字符串按连续相同字母一段进行分割存words里,存储每段的起点和长度(由起点可以得到对应字母);
并统计每种字母出现次数,连续只算一次;
分类讨论:
1、不进行操作,那就是words里的最长长度;
2、长度可+1,例如aaaaaabbbbaa,字母为a的段出现过两次,可通过交换使长度+1;
3、两者可合并,可由其他位置填补,例如aaabaacccca,前三段中,第一段第三段相同,且第二段长度为1,并且a在别处也出现,可达长度为 第一段+第三段+1
4、两者可合并,但没其他可补,例如aaabaaccc,只能中间的b和第一段或第三段中一个进行更换,可达长度为 第一段+第三段
记录其中最大值即是答案。
代码
class Solution {
public:
int maxRepOpt1(string text) {
int n = text.size();
if(n == 1) return 1;
vector<pair<int, int> > words; //存每段起点和长度
unordered_map<char, int> hash; //字母及出现次数
int ans = 0, cnt = 1, begin = 0;
for(int i = 1; i < n; i++) {
if(text[i] == text[begin]) cnt++;
else {
words.push_back({begin, cnt});
hash[text[begin]]++;
begin = i;
ans = max(ans, cnt);
cnt = 1;
}
}
words.push_back({begin, cnt});
hash[text[begin]]++;
ans = max(ans, cnt);
int wordn = words.size();
if(wordn < 3) return ans;
for(auto [b, l] : words) { //每段能否多1
if(hash[text[b]] > 1) ans = max(ans, l + 1);
}
for(int i = 2; i < wordn; i++) { //两段可拼接,两边一样且中间长度为1
if(text[words[i-2].first] == text[words[i].first] && words[i-1].second == 1) {
if(hash[text[words[i].first]] > 2) ans = max(ans, words[i-2].second + words[i].second + 1);
else ans = max(ans, words[i-2].second + words[i].second);
}
}
return ans;
}
};