字符串 S 由小写字母组成。我们要把这个字符串划分为尽可能多的片段,同一字母最多出现在一个片段中。返回一个表示每个字符串片段的长度的列表。
输入:S = “ababcbacadefegdehijhklij”
输出:[9,7,8]
解释:
划分结果为 “ababcbaca”, “defegde”, “hijhklij”。
每个字母最多出现在一个片段中。
像 “ababcbacadefegde”, “hijhklij” 的划分是错误的,因为划分的片段数较少。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/partition-labels
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
此题思路是首先记录下所有字母最后出现的位置,使用一个长度为26的数组,时间复杂度为O(n)。
然后从前向后遍历这个字符串,使用两个变量left和last。left表示子串的开头位置,last表示子串中所有的字母最后一此出现的位置的最大值。
比如子串为abc时,其中a最后一次出现在5位置,b最后出现在7位置,c最后出现在6位置,则last为7,这样向后遍历到7位置,如果遍历过程中出现一个字母,其最后一次出现的位置还在7后面,则更新last值,直到某个last位置,子串中所有字母最后一次出现的位置都不超过这个位置,即得到一个最大子串。
class Solution {
public List<Integer> partitionLabels(String s) {
//存储字母最后一次出现的位置
int[] ans=new int[26];
int len=s.length();
for(int i=0;i<len;i++){
ans[s.charAt(i)-'a']=i;
}
int left=0;
List<Integer> list=new ArrayList<>();
int last=ans[s.charAt(0)-'a'];
for(int i=1;i<len;i++){
if(last<i){
//子串中所有字母最后一次出现的位置都在i前面,则找到了一个子串
list.add(i-left);
//新子串以i开头
left=i;
//更新last
last=ans[s.charAt(i)-'a'];
}else{
//更新last
last=Math.max(last,ans[s.charAt(i)-'a']);
}
}
list.add(len-left);
return list;
}
}