Problem: 3713. 最长的平衡子串 I
文章目录
- [1. 整体思路](#1. 整体思路)
- [2. 完整代码](#2. 完整代码)
- [3. 时空复杂度](#3. 时空复杂度)
-
-
- [时间复杂度: O ( N 2 ) O(N^2) O(N2)](#时间复杂度: O ( N 2 ) O(N^2) O(N2))
- [空间复杂度: O ( 1 ) O(1) O(1) 或 O ( N ) O(N) O(N)](#空间复杂度: O ( 1 ) O(1) O(1) 或 O ( N ) O(N) O(N))
-
1. 整体思路
核心问题
寻找最长子串 s[i...j],使得该子串中所有出现过的字符的出现次数都相同。
算法逻辑:优化的暴力枚举
-
枚举所有子串:
- 依然使用双重循环遍历所有子串
[i, j]。
- 依然使用双重循环遍历所有子串
-
实时维护最大频率和字符种类数:
- 在内层循环中,我们不需要每次都遍历
cnt数组来检查平衡性。 - 我们维护两个关键变量:
max:当前子串[i, j]中出现的最大频率 。每当某个字符频率增加时,更新max。diff:当前子串[i, j]中出现的不同字符的个数 (Different Characters)。每当某个字符频率从 0 变为 1 时,diff++。
- 在内层循环中,我们不需要每次都遍历
-
快速判断平衡性:
- 如果一个子串是平衡的,意味着其中所有
diff种字符的出现次数都必须相等,且必须等于最大频率max。 - 因此,子串的总长度
len = j - i + 1必须等于max * diff。 - 判断公式 :
max * diff == len。- 如果相等,说明所有出现的字符频率都是
max,子串平衡。更新ans。 - 如果不相等,说明有些字符频率小于
max,子串不平衡。
- 如果相等,说明所有出现的字符频率都是
- 如果一个子串是平衡的,意味着其中所有
2. 完整代码
java
class Solution {
public int longestBalanced(String s) {
// 转换为字符数组,提高访问效率
char[] cs = s.toCharArray();
int n = cs.length;
int ans = 0;
// 1. 枚举子串起始位置 i
for (int i = 0; i < n; i++) {
// cnt 数组用于统计当前子串 [i, j] 中每个字符的频率
int[] cnt = new int[26];
// max: 当前子串中的最大频率
int max = 0;
// diff: 当前子串中出现的不同字符种类数
int diff = 0;
// 2. 枚举子串结束位置 j
for (int j = i; j < n; j++) {
int b = cs[j] - 'a'; // 当前字符索引
// 如果这是该字符第一次出现,说明遇到了一种新字符
if (cnt[b] == 0) {
diff++;
}
// 更新当前字符的频率,并尝试更新最大频率 max
max = Math.max(max, ++cnt[b]);
// 3. 快速判断平衡性
// 子串长度 len = j - i + 1
// 理想总长度 = 最大频率 * 不同字符数
// 如果两者相等,说明所有字符的频率都必须是 max,即平衡
if (max * diff == j - i + 1) {
ans = Math.max(ans, j - i + 1);
}
}
}
return ans;
}
}
3. 时空复杂度
假设字符串长度为 N N N。
时间复杂度: O ( N 2 ) O(N^2) O(N2)
- 计算依据 :
- 双重循环枚举子串,总次数为 N ( N + 1 ) 2 \frac{N(N+1)}{2} 2N(N+1)。
- 内部所有操作(更新
cnt,max,diff, 判断)均为 O ( 1 ) O(1) O(1) 的常数操作。
- 结论 : O ( N 2 ) O(N^2) O(N2)。
- 相比上一版消除了 C = 26 C=26 C=26 的因子。
空间复杂度: O ( 1 ) O(1) O(1) 或 O ( N ) O(N) O(N)
- 计算依据 :
cnt数组固定大小 26。toCharArray需要 O ( N ) O(N) O(N) 空间。如果不计输入副本,额外空间为 O ( 1 ) O(1) O(1)。
- 结论 : O ( N ) O(N) O(N)。