题目名称:划分字母区间
给你一个字符串 s 。我们要把这个字符串划分为尽可能多的片段,同一字母最多出现在一个片段中。
注意,划分结果需要满足:将所有划分结果按顺序连接,得到的字符串仍然是 s 。
返回一个表示每个字符串片段的长度的列表。
示例 1:
输入: s = "ababcbacadefegdehijhklij"
输出: [9,7,8]
解释:
划分结果为 "ababcbaca"、"defegde"、"hijhklij" 。
每个字母最多出现在一个片段中。
像 "ababcbacadefegde", "hijhklij" 这样的划分是错误的,因为划分的片段数较少。
示例 2:
输入: s = "eccbbbbdec"
输出: [10]
提示:
1 <= s.length <= 500s仅由小写英文字母组成
思路分析
遍历一遍找到每个字母出现的最后位置 第二次遍历不断更新中止下标end,end = Math.max(end,last[char]) 直到end后无重复字母 得出一个区间 这样划分的区间是最多的
从i出开始遍历,判断当前遍历是否超出了记录的最远处值,如果未超过,更新bound,且继续向后遍历,如果超出了,说明可以划分一个区间。 举例说明,我们首先记录每个字母出现的最远位置。然后,对于"ababcbacadefegdehijhklij"来说,我们首先从a开始,a出现的最远位置索引为8,bound记做8。继续向后遍历,遍历到b,b出现的最远距离为5,bound不需要更新,继续向后,后面依次,直到索引遍历到8,说明之前的字母的索引值最大即到此,可以做出一个划分。然后更新起始位置,继续做如上的操作。 本题中,我们用i表示开始,cur表示当前遍历的位置。当可以做出一个划分时,片段长度为cur-i+1,然后更新i = cur + 1
Code实现
public List < Integer > partitionLabels(String S) {
char[] arr = S.toCharArray();
int[] local = new int[26];
for (int i = 0; i < 26; i++) {
local[i] = -1;
}
for (int i = 0; i < arr.length; i++) {
local[arr[i] - 'a'] = i;
}
List < Integer > res = new ArrayList < > ();
int i = 0;
while (i < arr.length) {
int cur = i;
int bound = local[arr[cur] - 'a'];
while (cur < bound) {
cur++;
bound = Math.max(bound, local[arr[cur] - 'a']);
}
res.add(cur - i + 1);
i = cur + 1;
}
return res;
}
结果
算法复杂度分析
- 时间复杂度:
- 空间复杂度: