题目描述
给你一个字符串 s 。我们要把这个字符串划分为尽可能多的片段,同一字母最多出现在一个片段中。例如,字符串 “ababcc” 能够被分为 [“abab”, “cc”],但类似 [“aba”, “bcc”] 或 [“ab”, “ab”, “cc”] 的划分是非法的。
注意,划分结果需要满足:将所有划分结果按顺序连接,得到的字符串仍然是 s 。
返回一个表示每个字符串片段的长度的列表。
示例:
输入:s = “ababcbacadefegdehijhklij”
输出:[9,7,8]
题目分析
先枚举一遍,记录每个字母的最后一个位置。
根据第一个位置,确定第一个区间的 start 和 end,向右枚举,过程中检查当前字母的 last 是否超出 end,超出则更新 end。
当枚举位置到达 end 时,说明这是一个符合条件的区间的终点,将区间长度保存下来,然后处理下一个区间。
时间复杂度 O(n).
Java
public List<Integer> partitionLabels(String s) {
List<Integer> ans = new ArrayList<>();
int[] last = new int[30];
for (int i = 0; i < s.length(); i++) {
last[s.charAt(i) - 'a'] = i;
}
int start = 0, end = last[s.charAt(0) - 'a'];
for (int i = 0; i < s.length(); i++) {
end = Math.max(end, last[s.charAt(i) - 'a']);
if (i == end) {
ans.add(end - start + 1);
start = end + 1;
}
}
return ans;
}
Kotlin
fun partitionLabels(s: String): List<Int> {
val map = IntArray(30)
val ans = ArrayList<Int>()
for (i in s.indices) {
map[s[i] - 'a'] = i
}
// 分段起点和终点
var start = 0
var end = map[s[0] - 'a']
for (i in s.indices) {
end = max(end, map[s[i] - 'a'])
// 当前是本段最后一个
if (i == end) {
ans.add(end - start + 1)
start = end + 1
}
}
return ans
}