问题背景
给你一个字符串
s
s
s。我们要把这个字符串划分为尽可能多的片段,同一字母最多出现在一个片段中。
注意,划分结果需要满足:将所有划分结果按顺序连接,得到的字符串仍然是
s
s
s。
返回一个表示每个字符串片段的长度的列表。
数据约束
●
1
≤
s
.
l
e
n
g
t
h
≤
500
1 \le s.length \le 500
1≤s.length≤500
●
s
s
s 仅由小写英文字母组成
解题过程
看到频率和子串,一开始想的是滑窗搭配哈希表,实际上并不是很好实现。
比较好的做法是,找到所有字母第一次和最后一次出现的位置,把这个问题看作 合并区间。
每个字母第一次和最后一次出现的位置会框定一个范围,这些范围里还会包含其它字母,也就产生了重叠区间。为了使得同一字母最多出现在一个片段中,这些重叠区间是需要合并的。
而题目又要求划分为尽可能多的片段,就不应该进一步地尝试合并区间了,所以上述处理完的区间长度就是最终结果。
具体实现
class Solution {
public List<Integer> partitionLabels(String s) {
char[] chS = s.toCharArray();
int n = chS.length;
// 统计每一个字母最后一次出现的位置
int[] lastIndex = new int[26];
for (int i = 0; i < n; i++) {
lastIndex[chS[i] - 'a'] = i;
}
List<Integer> res = new ArrayList<>();
for (int i = 0, left = 0, right = 0; i < n; i++) {
// 更新当前有边界的要求
right = Math.max(right, lastIndex[chS[i] - 'a']);
// 访问到当前的有边界时,说明已经完成了区间合并,添加结果并移动左边界指针
if (i == right) {
res.add(right - left + 1);
left = i + 1;
}
}
return res;
}
}