763. 划分字母区间
贪心算法
思路
一个字母要在同一个片段里,所以同一个字母第一次出现的位置和最后一次出现的位置在同一个片段中。所以先遍历一遍,获得每个字母最后一次出现的位置。
接下来,将字符串划分成尽可能多的片段:
- 对于每个被访问的字母 a a a,取得当前字母 a a a 最后一次出现的位置 e n d c end_c endc,那么当前片段结束下标一定不小于 e n d c end_c endc,因此 e n d = m a x ( e n d , e n d c ) end = max(end,end_c) end=max(end,endc)。
- 当访问到下标 e n d end end 时,当前片段访问结束,长度为 e n d − s t a r t + 1 end-start+1 end−start+1,将长度添加到返回数组,然后令 s t a r t = e n d + 1 start=end+1 start=end+1,继续寻找下一个片段
- 重复上述过程,直到遍历完字符串。
代码实现
class Solution
{
public:
vector<int> partitionLabels(string s)
{
int start = 0, end = 0;
int last[26];
vector<int> res;
// 寻找每个字母最后出现的位置
for (int i = 0; i < s.size(); i++)
{
last[s[i] - 'a'] = i;
}
// 使用贪心的方法将字符串划分为尽可能多的片段
for (int i = 0; i < s.size(); i++)
{
end = max(end, last[s[i] - 'a']);
if (end == i)
{
res.push_back(end - start + 1);
start = end + 1;
}
}
return res;
}
};
复杂度分析
- 时间复杂度: O ( n ) O(n) O(n),其中 n n n 是字符串的长度。需要遍历字符串两次,第一次遍历时记录每个字母最后一次出现的下标位置,第二次遍历时进行字符串的划分。
- 空间复杂度: O ( ∣ Σ ∣ ) O(|\Sigma|) O(∣Σ∣),其中 Σ \Sigma Σ 是字符串中的字符集。这道题中,字符串只包含小写字母,因此 ∣ Σ ∣ = 26 |\Sigma|=26 ∣Σ∣=26。