Medium
题目描述
给你一个只包含字符 ‘a’、‘b’ 和 ‘c’ 的字符串 s。
如果一个子串中所有不同字符出现的次数相同,则称该子串为平衡的。
返回 s 的最长平衡子串的长度。
示例 1:
输入:s = "abbac"
输出:4
解释:最长平衡子串是 "abba",因为不同字符 'a' 和 'b' 都恰好出现 2 次。
示例 2:
输入:s = "aabcc"
输出:3
解释:最长平衡子串是 "abc",因为所有不同字符 'a'、'b' 和 'c' 都恰好出现 1 次。
示例 3:
输入:s = "aba"
输出:2
解释:最长平衡子串之一是 "ab",因为不同字符 'a' 和 'b' 都恰好出现 1 次。另一个最长平衡子串是 "ba"。
约束条件:
- 1 <= s.length <= 10^5
- s 只包含字符 ‘a’、‘b’ 和 ‘c’
解题思路
这道题需要分三种情况来考虑:
情况1:单个字符 最长的平衡子串就是连续相同字符的最长序列,因为只有一个字符时它必然平衡。
情况2:两个不同字符 对于任意两个字符的组合,我们可以忽略第三个字符,只关注这两个字符。使用前缀和的差值来判断平衡性:如果在两个位置上两个字符的计数差值相同,那么这两个位置之间的子串是平衡的。
情况3:三个字符都存在
使用前缀计数和哈希表。我们用 (count_b - count_a, count_c - count_a) 作为键值,如果同样的键值在两个不同位置出现,说明这两个位置之间的子串中三个字符的出现次数相等。
核心思路是将问题分解为三个子问题,分别求解后取最大值。对于情况2和3,我们利用前缀和的性质:如果两个前缀的字符计数差值相同,那么它们之间的子串是平衡的。
代码实现
class Solution {
public:
int longestBalanced(string s) {
int n = s.length();
int maxLen = 0;
// Case 1: Single character
int currentLen = 1;
for (int i = 1; i < n; i++) {
if (s[i] == s[i-1]) {
currentLen++;
} else {
maxLen = max(maxLen, currentLen);
currentLen = 1;
}
}
maxLen = max(maxLen, currentLen);
// Case 2: Two distinct characters
vector<pair<char, char>> pairs = {{'a', 'b'}, {'a', 'c'}, {'b', 'c'}};
for (auto& p : pairs) {
char c1 = p.first, c2 = p.second;
unordered_map<int, int> diffMap;
diffMap[0] = -1;
int diff = 0;
for (int i = 0; i < n; i++) {
if (s[i] == c1) diff++;
else if (s[i] == c2) diff--;
if (diffMap.count(diff)) {
maxLen = max(maxLen, i - diffMap[diff]);
} else {
diffMap[diff] = i;
}
}
}
// Case 3: All three characters
map<pair<int, int>, int> stateMap;
stateMap[{0, 0}] = -1;
int countA = 0, countB = 0, countC = 0;
for (int i = 0; i < n; i++) {
if (s[i] == 'a') countA++;
else if (s[i] == 'b') countB++;
else countC++;
pair<int, int> state = {countB - countA, countC - countA};
if (stateMap.count(state)) {
maxLen = max(maxLen, i - stateMap[state]);
} else {
stateMap[state] = i;
}
}
return maxLen;
}
};
class Solution:
def longestBalanced(self, s: str) -> int:
n = len(s)
max_len = 0
# Case 1: Single character
current_len = 1
for i in range(1, n):
if s[i] == s[i-1]:
current_len += 1
else:
max_len = max(max_len, current_len)
current_len = 1
max_len = max(max_len, current_len)
# Case 2: Two distinct characters
pairs = [('a', 'b'), ('a', 'c'), ('b', 'c')]
for c1, c2 in pairs:
diff_map = {0: -1}
diff = 0
for i, char in enumerate(s):
if char == c1:
diff += 1
elif char == c2:
diff -= 1
if diff in diff_map:
max_len = max(max_len, i - diff_map[diff])
else:
diff_map[diff] = i
# Case 3: All three characters
state_map = {(0, 0): -1}
count_a = count_b = count_c = 0
for i, char in enumerate(s):
if char == 'a':
count_a += 1
elif char == 'b':
count_b += 1
else:
count_c += 1
state = (count_b - count_a, count_c - count_a)
if state in state_map:
max_len = max(max_len, i - state_map[state])
else:
state_map[state] = i
return max_len
public class Solution {
public int LongestBalanced(string s) {
int n = s.Length;
int maxLen = 0;
// Case 1: Single character
int currentLen = 1;
for (int i = 1; i < n; i++) {
if (s[i] == s[i-1]) {
currentLen++;
} else {
maxLen = Math.Max(maxLen, currentLen);
currentLen = 1;
}
}
maxLen = Math.Max(maxLen, currentLen);
// Case 2: Two distinct characters
char[,] pairs = {{'a', 'b'}, {'a', 'c'}, {'b', 'c'}};
for (int p = 0; p < 3; p++) {
char c1 = pairs[p, 0], c2 = pairs[p, 1];
var diffMap = new Dictionary<int, int> {{0, -1}};
int diff = 0;
for (int i = 0; i < n; i++) {
if (s[i] == c1) diff++;
else if (s[i] == c2) diff--;
if (diffMap.ContainsKey(diff)) {
maxLen = Math.Max(maxLen, i - diffMap[diff]);
} else {
diffMap[diff] = i;
}
}
}
// Case 3: All three characters
var stateMap = new Dictionary<(int, int), int> {[(0, 0)] = -1};
int countA = 0, countB = 0, countC = 0;
for (int i = 0; i < n; i++) {
if (s[i] == 'a') countA++;
else if (s[i] == 'b') countB++;
else countC++;
var state = (countB - countA, countC - countA);
if (stateMap.ContainsKey(state)) {
maxLen = Math.Max(maxLen, i - stateMap[state]);
} else {
stateMap[state] = i;
}
}
return maxLen;
}
}
var longestBalanced = function(s) {
const n = s.length;
let maxLen = 0;
// Case 1: Single character
let currentLen = 1;
for (let i = 1; i < n; i++) {
if (s[i]
复杂度分析
| 复杂度 | 分析 |
|---|---|
| 时间复杂度 | O(n) |
| 空间复杂度 | O(n) |
其中 n 是字符串的长度。每种情况都只需要遍历字符串一次,哈希表的大小最多为 O(n)。