[路飞]_划分字母区间

197 阅读2分钟

「这是我参与2022首次更文挑战的第5天,活动详情查看:2022首次更文挑战

763. 划分字母区间

题目

字符串 S 由小写字母组成。我们要把这个字符串划分为尽可能多的片段,同一字母最多出现在一个片段中。返回一个表示每个字符串片段的长度的列表。

示例

输入:S = "ababcbacadefegdehijhklij"
输出:[9,7,8]
解释:
划分结果为 "ababcbaca", "defegde", "hijhklij"。
每个字母最多出现在一个片段中。
像 "ababcbacadefegde", "hijhklij" 的划分是错误的,因为划分的片段数较少。

题解

贪心

  • 题目要求字符串划分为尽可能多的片段
  • 已知同一字母最多出现在一个片段中,所以要字符串划分为尽可能多的片段,需要知道字符最后一次出现的下标,字符串第一次出现与最后一次出现一定要在一个片段内;
  • 有因为字符串是由小写字母组成,所以字符最多有26种。根据这个已知条件,可以使用一个长度为26的数组indexList保存字符串最后一次出现的下标;
  • 枚举字符串S,将字符串最后一次出现的下标存放到indexList;
  • 在indexList中,假设任意字符s在indexList数组中最后一次出现的下标为endsend_s,
  • 任意一个片段[s1s_1,...,sns_n],片段中的字符最后一次出现的下标[ends1end_{s1},endsnend_{sn}],在[ends1end_{s1},endsnend_{sn}]一定存在endmaxend_{max},
  • 从start= 0 开始,枚举整个字符串,当endmaxend_{max}与枚举下标i相同时,可以认为这是一个最小的不可再分割的片段,将该片段长度放入结果数组中,i - start + 1
  • 从start = i+1位置开始,继续枚举字符串S,当endmaxend_{max}再次与枚举下标i相同时,找到另一个最小不可分割的片段,直到枚举结束
  • 返回结果

根据上述思路编辑代码如下:

代码

var partitionLabels = function (s) {
  // 记录字符最后一次出现的坐标
  const indexList = Array(26).fill(0)
  for (let i = 0; i < s.length; i++) {
    const index = s[i].charCodeAt() - 'a'.charCodeAt()
    indexList[index] = i
  }

  let start = 0
  let end = 0
  const result = []
  for (let i = 0; i < s.length; i++) {
    const index = s[i].charCodeAt() - 'a'.charCodeAt()
    end = Math.max(end, indexList[index])
    if (end === i) {
      result.push(end - start + 1)
      start = end + 1
    }
  }
  return result
}