echo

任生命穿梭 时间的角落

0%

划分字母区间

763. 划分字母区间

字符串 S 由小写字母组成。我们要把这个字符串划分为尽可能多的片段,同一个字母只会出现在其中的一个片段。返回一个表示每个字符串片段的长度的列表。

示例 1:

1
2
3
4
5
6
输入:S = "ababcbacadefegdehijhklij"
输出:[9,7,8]
解释:
划分结果为 "ababcbaca", "defegde", "hijhklij"。
每个字母最多出现在一个片段中。
像 "ababcbacadefegde", "hijhklij" 的划分是错误的,因为划分的片段数较少。

提示:

  • S的长度在[1, 500]之间。
  • S只包含小写字母 'a''z'

同一个字母只能出现在同一片段,同一个字母第一次出现的下标位置和最后一次出现的下标位置必须出现在同一片段。因此,需要遍历字符串,得到每个字母最后一次出现的下标位置。

接下来使用贪心算法和双指针的方法将字符串划分为尽可能多的片段:

  • 从左到右遍历字符串,遍历的同时维护当前片段的开始下标 start 和结束下标 end。
  • 对于每个访问到的字母 c,得到当前字母最后一次出现的下标位置 endc,则当前片段的结束下标一定不会小于 endc,end = max(end, endc)。
  • 当访问到下标 end 时,当前片段访问结束,当前判断的长度为 end - start + 1,将当前片段的长度添加到返回值,然后令 start = end + 1,继续寻找下一个片段。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Solution {
public List<Integer> partitionLabels(String S) {
int[] last = new int[26];
for(int i = 0; i < S.length(); i++){
last[S.charAt(i) - 'a'] = i;
}
List<Integer> partition = new ArrayList<Integer>();
int start = 0, end = 0;
for(int i = 0; i < S.length(); i++){
end = Math.max(end, last[S.charAt(i) - 'a']);
if(i == end){
partition.add(end - start + 1);
start = end + 1;
}
}
return partition;
}
}
  • 时间复杂度O(n)
  • 空间复杂度O(1)
Powered By Valine
v1.5.2