题目来源:https://leetcode.cn/problems/partition-labels/description/
C++题解1: 先遍历一遍使用哈希算法找到每个小写字母的最远的索引,再遍历一次,不断更新每个片段的最远距离。
class Solution {
public:
vector<int> partitionLabels(string s) {
int len = s.size();
vector<int> inds(26, 0);
for(int i = 0; i < len; i++){
int ind = s[i] - 'a';
inds[ind] = i;
}
vector<int> res;
for(int j = 0; j < len; j++){
int count = 1;
int end = inds[s[j] - 'a'];
if(j == end) res.push_back(count);
else {
for(int k = j+1; k <= end; k++) {
end = max(end, inds[s[k] - 'a']);
}
count = end - j + 1;
res.push_back(count);
j = end;
}
}
return res;
}
};
C++题解2(来源代码随想录):记录每个字母开始与结束的索引,用不重复区间的方式解题。将区间按左边界从小到大排序,找到边界将区间划分成组,互不重叠。找到的边界就是答案。
class Solution {
public:
static bool cmp(vector<int> &a, vector<int> &b) {
return a[0] < b[0];
}
// 记录每个字母出现的区间
vector<vector<int>> countLabels(string s) {
vector<vector<int>> hash(26, vector<int>(2, INT_MIN));
vector<vector<int>> hash_filter;
for (int i = 0; i < s.size(); ++i) {
if (hash[s[i] - 'a'][0] == INT_MIN) {
hash[s[i] - 'a'][0] = i;
}
hash[s[i] - 'a'][1] = i;
}
// 去除字符串中未出现的字母所占用区间
for (int i = 0; i < hash.size(); ++i) {
if (hash[i][0] != INT_MIN) {
hash_filter.push_back(hash[i]);
}
}
return hash_filter;
}
vector<int> partitionLabels(string s) {
vector<int> res;
// 这一步得到的 hash 即为无重叠区间题意中的输入样例格式:区间列表
// 只不过现在我们要求的是区间分割点
vector<vector<int>> hash = countLabels(s);
// 按照左边界从小到大排序
sort(hash.begin(), hash.end(), cmp);
// 记录最大右边界
int rightBoard = hash[0][1];
int leftBoard = 0;
for (int i = 1; i < hash.size(); ++i) {
// 由于字符串一定能分割,因此,
// 一旦下一区间左边界大于当前右边界,即可认为出现分割点
if (hash[i][0] > rightBoard) {
res.push_back(rightBoard - leftBoard + 1);
leftBoard = hash[i][0];
}
rightBoard = max(rightBoard, hash[i][1]);
}
// 最右端
res.push_back(rightBoard - leftBoard + 1);
return res;
}
};