题目描述:

题目解析:
题目要求对字符串进行分割,使得每个字母最多只出现在一个分割片段中 。
在满足这个条件的前提下,需要返回每个分割片段的长度。
换句话说:
-
同一个字符不能跨越多个片段
-
一旦某个字符出现在当前片段中,那么这个片段必须包含该字符在字符串中的所有出现位置
-
分割后的片段要尽可能靠前、数量尽可能多
因此,本题的本质并不是"随意切字符串",而是要找到一种合理的切分方式,使字符的出现范围不会被打断。
思路分析:
解决这道题的关键,在于提前知道每个字符最远会出现到哪里。
1. 预处理字符的最后位置
由于字符串只包含小写字母,可以先遍历字符串,记录每个字符在字符串中最后一次出现的下标。
这样一来,当我们在某个位置看到一个字符时,就能立刻知道:当前分割区间至少要延伸到这个字符的最后出现位置。
2. 用区间合并的思路遍历字符串
接下来,从左到右遍历字符串,并维护一个"当前分割区间":区间的左端点是当前片段的起始位置。区间的右端点表示:当前片段必须覆盖到的最远位置。在遍历过程中,每遇到一个字符,就用它的最后出现位置来更新当前区间的右端点,保证这个字符不会出现在区间之外。
3. 何时可以完成一次分割
当遍历位置刚好走到当前区间的右端点时,说明:当前片段中出现的所有字符都已经完整地包含在这个区间内不会再延伸到后面的位置此时就可以安全地切分出一个片段,记录它的长度,并从下一个位置开始新的片段。
4. 思路本质
从整体来看,这道题的核心思想可以概括为:先确定每个字符的"活动范围",再把这些范围不断合并成若干不重叠的区间,每一个最终合并完成的区间,就是一个合法的分割片段
代码:
java
class Solution {
public List<Integer> partitionLabels(String s) {
char[] a=s.toCharArray();
int n=a.length;
int[] last=new int[26];
for(int i=0;i<n;i++){
last[a[i]-'a']=i;
}
List<Integer> res=new ArrayList<>();
int start=0,end=0;
for(int i=0;i<n;i++){
end=Math.max(last[a[i]-'a'],end);
if(i==end){
res.add(end-start+1);
start=end+1;
}
}
return res;
}
}