题目描述
给定一个字符串 text
,允许交换字符串中的任意两个字符。找到最长的单字符重复的子串的长度。
样例
输入:text = "ababa"
输出:3
解释:我们可以交换第一个 'b' 和最后一个 'a',或者第一个 'a' 和最后一个 'b'。
然后,最长的单字符重复的子串 "aaa" 的长度就是 3。
输入:text = "aaabaaa"
输出:6
解释:交换 'b' 和最后一个 'a' (或第一个 'a'),
我们得到最长的单字符重复的子串 "aaaaaa" 的长度就是 6
输入:text = "aaabbaaa"
输出:4
输入:text = "aaaaa"
输出:5
解释:没有必要交换字符,我们得到的最长的单字符重复的子串就是 "aaaaa",长度为 5。
输入:text = "abcdef"
输出:1
限制
1 <= text.length <= 20000
text
仅由小写英文字母组成。
算法
(动态规划) O(n)
- 我们分别考察每种字符所能得到的最大答案。
- 假设我们当前考察的是字符
c
。我们通过遍历一次数组的方式,找到单字符就是c
的情况下的最长单重复子串。 - 设
cnt
为字符串中c
出现的次数;f(i) 表示以 i 结尾且没有替换过不是c
的字符时的最长但重复子串;g(i) 表示以 i 结尾且替换过不是c
的字符时的最长但重复子串。 - 当
c == text[i]
时,累加cnt
,f(i)=f(i−1)+1,g(i)=g(i−1)+1,也就是都可以沿着上一次的结果往后累加 1 的长度。 - 如果
c != text[i]
,则 g(i)=f(i−1)+1,表示我们强制替换text[i]
的字符为c
(注意不是交换),所以要从没有替换过的 f 数组转移;f(i)=0,表示如果不替换,那么长度只能归 0。交换只是替换的一种特殊形式,我们都先假设总能交换。如果不能交换,如aaabaaa
我们无法把中间的b
用一个新的a
交换时,可以通过答案不能超过cnt
来特判。 - 答案为 min,也就是所有的 f 和 g 的最大值,但结果不能超过
cnt
。 - 这里的 f 和 g 数组因为之和上一位有关,所以可以化简为变量。
时间复杂度
- 枚举每种字符时,只需要遍历数组一次,故时间复杂度为 O(n)。
空间复杂度
- 优化后,只需要常数个变量,故空间复杂度为 O(1)。
C++ 代码
class Solution {
public:
int solve(char c, const string& text) {
int n = text.length(), tot = 0;
int f = 0, g = 0, cnt = 0;
for (int i = 0; i < n; i++) {
if (c == text[i]) {
f++;
g++;
cnt++;
} else {
g = f + 1;
f = 0;
}
tot = max(tot, max(f, g));
}
return min(tot, cnt);
}
int maxRepOpt1(string text) {
int ans = 0;
for (char c = 'a'; c <= 'z'; c++)
ans = max(ans, solve(c, text));
return ans;
}
};
讲的很清楚,学习了!