763. 划分字母区间
字符串 S 由小写字母组成。我们要把这个字符串划分为尽可能多的片段,同一字母最多出现在一个片段中。返回一个表示每个字符串片段的长度的列表。
示例:
输入:S = “ababcbacadefegdehijhklij”
输出:[9,7,8] 解释: 划分结果为 “ababcbaca”, “defegde”, “hijhklij”。
每个字母最多出现在一个片段中。 像 “ababcbacadefegde”,“hijhklij” 的划分是错误的,因为划分的片段数较少。
按照前面的 452. 用最少数量的箭引爆气球 的思路直接来解的话,可以得到:
#include<string>
#include<vector>
#include<algorithm>
#include<iostream>
using namespace std;
class Solution {
public:
vector<int> partitionLabels(string S) {
vector<vector<int>>loc(26,vector<int>(2,-1));
vector<int>result;
vector<int>loc_lr(2, -1);
bool flag = false;
//1、获得各个字符的最左和最右的下标
for (int i = 0; i <= 'z' - 'a'; ++i)
{
for (int n = 0; n < S.length(); ++n)
{
if (S[n] == i + 'a')
{
flag = true;
loc_lr[0] = (loc_lr[0]>=0&&loc_lr[0] < n) ? loc_lr[0] : n;
loc_lr[1] = loc_lr[1] > n ? loc_lr[1] : n;
}
}
if (flag == true)
{
loc[i ] = loc_lr;
loc_lr[0] = -1; loc_lr[1] = -1;
flag = false;
}
}
//2、对每个字符下标向量进行排序
sort(loc.begin(), loc.end(), [=](const vector<int>a, vector<int>b) {
return a[0]>b[0];
});
int ed = 0;
for (int i = 25; i >= 0; --i)
{
if (loc[i][0] != -1)
{
ed = i;
break;
}
}
//3、获得每一段存在重合段的段长,需要注意最后一段需要单独处理
//由于下标是连续的,所以上一段最低点减去上一段最低点就是段长
int head = loc[ed][1];
int tail = loc[ed][0];
for (int j = ed; j >=0 ; --j)
{
if (head < loc[j][0])
{
result.push_back(loc[j][0]-tail);
tail = loc[j][0];
}
head = max(head, loc[j][1]);
}
result.push_back(head +1 - tail);
return result;
}
};
int main()
{
Solution kill;
string S = "ababcbacadefegdehijhklij";
vector<int>result = kill.partitionLabels(S);
for (int re : result)
cout << re << " ";
return 0;
}
但是,这道题是取每一段的长度,而不是统计有多少个段。
在遍历的过程中相当于是要找每一个字母的边界,「如果找到之前遍历过的所有字母的最远边界,说明这个边界就是分割点了」。此时前面出现过所有字母,最远也就到这个边界了。
可以分为如下两步:
1、统计每一个字符最后出现的位置;
2、从头遍历字符,并更新字符的最远出现下标,如果找到字符最远出现位置下标和当前下标相等了,则找到了分割点。
class Solution {
public:
vector<int> partitionLabels(string S) {
int hash[26] = {0}; // i为字符,hash[i]为字符出现的最后位置
for (int i = 0; i < S.size(); i++) { // 统计每一个字符最后出现的位置
hash[S[i] - 'a'] = i;
}
vector<int> result;
int left = 0;
int right = 0;
for (int i = 0; i < S.size(); i++) {
right = max(right, hash[S[i] - 'a']); // 找到字符出现的最远边界
if (i == right) {
result.push_back(right - left + 1);
left = i + 1;
}
}
return result;
}
};