LeetCode-763如何为?
摘要:本题在线练习:LeetCode 763. 划分字母区间 - 在线练习(免费 · 无需登录 · AI 辅助)(https:onefly.topzero2Leetcodeplaygro
本题在线练习:LeetCode 763. 划分字母区间 - 在线练习(免费 · 无需登录 · AI 辅助)(https://onefly.top/zero2Leetcode/playground.html?id=763)
配套刷题网站 Zero2Leetcode - 内置本地 OJ + AI 教练,零门槛开刷 Hot 100。
题目概述
给定字符串 s,把它划分成尽可能多的片段,使得同一个字母最多出现在一个片段里。返回每个片段的长度。
例如:s = "ababcbacadefegdehijhklij" -> [9, 7, 8]
核心思路:先记录每个字符最后出现的位置
要求“同一个字母只能在一个片段里”,意味着:
如果某个片段里出现了字母 c,那么这个片段的右端点至少要延伸到 c 的最后出现位置,否则 c 会跑到下一段去,违规。
因此先预处理:
last[ch]:字符 ch 在字符串中最后一次出现的下标
然后贪心扫描维护当前片段的右端点:
end:当前片段必须覆盖到的最远右端点
扫描到位置 i 时,更新 end = max(end, last[s[i]])
当 i == end,说明当前片段内所有字符的最后出现位置都被覆盖到了,可以切一刀
代码实现
from typing import List
class Solution:
def partitionLabels(self, s: str) -> List[int]:
last = {}
for i, ch in enumerate(s):
last[ch] = i
res: List[int] = []
start = 0
end = 0
for i, ch in enumerate(s):
end = max(end, last[ch])
if i == end:
res.append(end - start + 1)
start = i + 1
return res
逐行拆解
last[ch] = i:记录字符最后出现位置
end = max(end, last[ch]):
当前段出现了字符 ch,段的右端点必须至少到 last[ch]
用 max 把所有出现过的字符需求合并起来
i == end:
表示段内所有字符的“最后一次出现”都不超过 end
当前段闭合,可以输出长度
手动模拟(关键片段)
以示例 "ababcbaca..." 开头为例:
a 最后出现位置在 8
b 最后出现位置在 5
c 最后出现位置在 7
扫描过程中 end 会被不断推到更远:
i=0 'a' -> end=8
i=1 'b' -> end=max(8,5)=8
...
当 i=8 时,i==end,第一段长度是 9
复杂度分析
时间复杂度:O(n)
空间复杂度:O(1)(字符集固定为小写字母时),一般写法按 O(n) 也可接受
总结
这题的贪心非常“干净”:
预处理每个字符最后出现位置
扫描时把当前段的右端点推到最远
扫到右端点就切段
本质是在做区间合并:每个字符产生一个覆盖区间 [first, last],最终切分点就是这些区间合并后的边界。
