力扣 763. 划分字母区间
给你一个字符串 s
。我们要把这个字符串划分为尽可能多的片段,同一字母最多出现在一个片段中。
注意,划分结果需要满足:将所有划分结果按顺序连接,得到的字符串仍然是 s
。
返回一个表示每个字符串片段的长度的列表。
示例 1:输入:s = "ababcbacadefegdehijhklij"
输出:[9,7,8]
解释:
划分结果为 "ababcbaca"、"defegde"、"hijhklij" 。
每个字母最多出现在一个片段中。
像 "ababcbacadefegde", "hijhklij" 这样的划分是错误的,因为划分的片段数较少。
示例 2:
输入:s = "eccbbbbdec"
输出:[10]
提示:
1 <= s.length <= 500
s
仅由小写英文字母组成
题解
因为要求"每个字母最多出现在一个片段中",所以对于同一个字母,所在片段应该包括它第一次出现到最后一次出现,所以需要记录每个字母最后一次出现的位置,
使用长度为26
的int
数组记录每个字母最后一次出现的位置,遍历s
,通过s[i]-'a'
得到在记录数组last_idx
中的下标。如s = "ababcbacadefegdehijhklij"
,得到a
对应的last_idx[0]=8
,即a
最后一次出现在下标8
,b
对应的last_idx[1]=5,b
最后一次在下标5
出现。
接下来划分片段,寻找每个片段可能的最小结束下标end
,同时需要变量记录开始下标start
。遍历s
,对于当前字母cur
,查询last_idx
得到最后一次出现的下标endCur
:
- 更新
end=max(end,endCur)
,更新当前区间的结束下标为原下标和endCur
较大的一个,因为当前元素最后一次在endCur
出现,那么当前区间的分割点>=endCur
,否则无法满足"每个字母最多出现在一个片段中"。
那么end
是如何保证为当前片段的结束下标呢?如先遍历a
,则end=enda=8
,即为了满足把a
都切在一个片段中,需要至少从8
开始切,接下来遍历到b
,end=enda>endb=5
,从8
开始切仍然可以满足把b
都切在一个片段中,如果在遍历到enda
之前,出现字母cur
的endCur>enda
,则end
更新为endCur
,表示即便从8
开始切割可以满足a和b
,但是无法满足字母cur
,所以当前区间需要在endCur
结束。
- 如果
i==end
,到达当前区间的结束下标,切割得到当前区间长度为end-start+1
,同时更新下一个区间的起始位置start
为当前区间结束下标end+1
。
如果还是不能理解可以看:https://www.youtube.com/watch?v=5NCjHqx2v-k
查看代码
class Solution {
public:
vector<int> partitionLabels(string s) {
int last_idx[26]={0};
//遍历s,更新26个字母最后一次出现的位置
for(int i=0;i<s.length();++i){
last_idx[s[i]-'a']=i;
}
//记录结果
vector<int> res;
int start=0;//区间开始下标
int end=0;//区间结束下标
for(int i=0;i<s.length();++i){
end=end>last_idx[s[i]-'a']?end:last_idx[s[i]-'a'];//更新区间的结尾为较大值
//当达到区间结尾了
if(i==end){
res.emplace_back(end-start+1);//记录区间长度
start=end+1;//更新区间开始下标
}
}
return res;
}
};