题目描述
字符串 S 由小写字母组成。我们要把这个字符串划分为尽可能多的片段,同一字母最多出现在一个片段中。返回一个表示每个字符串片段的长度的列表。
示例:
输入: S = "ababcbacadefegdehijhklij"
输出: [9,7,8]
解释:
划分结果为 "ababcbaca", "defegde", "hijhklij"。
每个字母最多出现在一个片段中。
像 "ababcbacadefegde", "hijhklij" 的划分是错误的,因为划分的片段数较少。
提示:
S的长度在[1, 500]之间。S只包含小写字母'a'到'z'。
解题思路
本题要求划分片段的时候同一个字母,只能出现在一个片段中,所以针对单个字母,我们可以找到它第一次出现的位置,和最后一次出现的位置,这样的一个区间划分为一个片段,就保证了它只出现在一个片段中。
但是因为这样的区间中可能会有其他的字母,所以我们也要保证其他的字母只出现在一个片段中,那这个问题怎么解决呢?
这里我们可以遍历输入字符串,记录每一个字母第一次出现的下标和最后一次出现的下标,这样数组遍历完成,就得到了每个字母出现的开始位置和结束位置。
因为我们是从前向后遍历数组的,所以每个区间的开始位置是单调递增的。而这个时候,我们记录前面字母区间结束位置的最大值,当后续的区间的开始值大于前面区间结束值的最大值,就说明前面区间中的字母,在后续的区间中都不会再出现,这个时候,前面的区间就可以划分为一个单独的片段了。而这样一个片段的长度就是所有区间结束值的最大值减去开始值的最小值+1。每次找到一个片段后计算片段长度插入结果数组,当我们遍历完所有的字母区间,就得到了本题的结果。
代码实现
var partitionLabels = function(s) {
const last = new Array(26);
const length = s.length;
const codePointA = 'a'.codePointAt(0);//记录字母a最后出现的位置
for(let i = 0 ; i < length; i++){
last[s.codePointAt(i) - codePointA] = i;
}
const partition = [];
let start = 0, end = 0; //定义合并之后起始终止位置
for(let i = 0; i < length; i++){
end = Math.max(end,last[s.codePointAt(i) - codePointA]);
if(i == end){
partition.push(end - start + 1);//求区间长度
start = end + 1;
}
}
return partition;
};
至此我们就完成了leetcode-763-划分字母区间