这是我参与2022首次更文挑战的第7天,活动详情查看:2022首次更文挑战
题目
763. 划分字母区间
字符串 S 由小写字母组成。我们要把这个字符串划分为尽可能多的片段,同一字母最多出现在一个片段中。返回一个表示每个字符串片段的长度的列表。
示例:
输入: S = "ababcbacadefegdehijhklij"
输出: [9,7,8]
解释:
划分结果为 "ababcbaca", "defegde", "hijhklij"。
每个字母最多出现在一个片段中。
像 "ababcbacadefegde", "hijhklij" 的划分是错误的,因为划分的片段数较少。
提示:
S的长度在[1, 500]之间。S只包含小写字母'a'到'z'。
思路
- 我们要根据片段来切割,然后相同字符的在同一个片段中,那么我们可以转换一下这个问题,先通过一轮遍历统计出每个元素最后一次出现在字符串中的位置;
- 由于题目中已经说了元素全部是小写字母,所以我们可以新建一个26位长度的数组来记录每个元素最后一次出现的位置,一开始默认值都是
-1表示没有出现过;当然如果这道题目没有说全部是小写字母怎么办呢,我们可以用map来记录,都差不多,只不过map每一轮需要get和set没有直接修改索引值来得直观; - 那么数组的下标怎么跟元素的
abcd进行关联呢,这道题目中我们可以通过charCodeAt方法来实现,这个方法是把小写字母转成数字的,不过转成数字后是从第97位开始的,前面的拿来存放其他字符了,而且是有序的并且与字母一一对应,所以我们只需要拿到每个位置的字符通过charCodeAt转换后就可以存入数组的下标中去,然后一轮for循环跑完,后面出现的值自然会覆盖前面的值,就实现了对最后出现的位置的统计; - 然后再跑一次
for循环,用三个变量来记录,prev记录上一个元素出现的位置,maxLen记录当前元素的最大长度,当我们走到一个位置的时候,判断一下是否已经是前面元素出现过的最大长度位置,如果是的话说明可以切割; - 那么我们只需要把当前索引
i减去上一轮出现的位置prev,就可以计算出长度了,把长度放到result数组中去即可。
实现
/**
* @param {string} s
* @return {number[]}
*/
var partitionLabels = function(s) {
const lastCharArr = new Array(26).fill(-1);
// 统计每个元素最后一次出现的位置
for (let i = 0; i < s.length; i++) {
const num = s[i].charCodeAt() - 97;
lastCharArr[num] = i;
}
// 索引0的位置也要算长度,所以初始值设置个-1
let prev = -1;
let maxLen = 0;
let result = [];
for (let i = 0; i < s.length; i++) {
const num = s[i].charCodeAt() - 97;
// 当前最长能走的距离 = 上一轮最长距离 或者 当前元素最长距离
maxLen = Math.max(maxLen, lastCharArr[num]);
// 当最长距离只能走到这了,说明可以切割了
if (maxLen <= i) {
result.push(maxLen - prev);
prev = maxLen;
maxLen = 0;
}
}
return result;
};
结果
看懂了的小伙伴可以点个关注、咱们下道题目见。如无意外以后文章都会以这种形式,有好的建议欢迎评论区留言。