给你一个字符串
s
。我们要把这个字符串划分为尽可能多的片段,同一字母最多出现在一个片段中。例如,字符串"ababcc"
能够被分为["abab", "cc"]
,但类似["aba", "bcc"]
或["ab", "ab", "cc"]
的划分是非法的。注意,划分结果需要满足:将所有划分结果按顺序连接,得到的字符串仍然是
s
。返回一个表示每个字符串片段的长度的列表。
解法 贪心+预处理
思路
题目的重点是同一字母最多出现在一个片段中,那就在遍历当前字符串的时候需要记录下来这个字符是否之前出现过。下面思考如果出现过,我们应该保存什么样的数据呢?
布尔值吗?如果保存布尔值,那只能判定当前子串不能添加到结果当中,并没有对结果有什么帮助。所以我们需要保存另外的数据。
除了布尔值,我们是不是可以保存这个字符的最后一次出现的索引。因为这样我们在遍历子串的时候就可以判断是否达到了这个字符的最远边界。如果是最远边界,那么就可以把这个子串加入到结果集当中。
所以整体思路就是预先处理一下所有字符的最远索引,然后遍历时维护两个变量来记录子串区间,如果当前字符已经到达最远索引,说明这个子串可以加入,并且要更新区间变量。
代码
function partitionLabels(s: string): number[] {
const map = new Map();
for (let i = 0; i < s.length; i++) {
map.set(s[i], i);
}
const result = [];
let start = 0;
let end = 0;
for (let i = 0; i < s.length; i++) {
end = Math.max(end, map.get(s[i]));
if (i === end) {
result.push(end - start + 1);
start = i + 1;
}
}
return result;
};
时空复杂度
时间复杂度:O(n)
空间复杂度:如果所有字符都唯一,那就是O(n)
,但只有 26 个字符,所以最多是 O(26)
,可以看作常数量级,渐进 O(1)