AI科技热点日报 | 2026年6月13日
2026/6/15 1:28:54
给你一个字符串s,要把这个字符串划分为尽可能多的片段,同一字母最多出现在一个片段中。例如ababcc能够被分为["abab", "cc"]。
示例 1:
输入:s = "ababcbacadefegdehijhklij" 输出:[9,7,8] 解释:划分为 "ababcbaca"、"defegde"、"hijhklij"示例 2:
输入:s = "eccbbbbdec" 输出:[10]| 思路 | 时间复杂度 | 空间复杂度 | 适用场景 |
|---|---|---|---|
| 哈希表存储 | O(n) | O(n) | 直观但稍繁琐 |
| 两遍遍历 | O(n) | O(1) | 本题最优解 |
第一遍用哈希表记录每个字符最后出现的位置。第二遍遍历时,维护当前片段中所有字符的最远边界。
classSolution{public:vector<int>partitionLabels(string s){unordered_map<char,int>last;for(inti=0;i<s.size();i++){last[s[i]]=i;}vector<int>ans;intstart=0,end=0;for(inti=0;i<s.size();i++){end=max(end,last[s[i]]);if(end==i){ans.push_back(end-start+1);start=end+1;}}returnans;}};用数组代替哈希表记录每个字符最后出现的位置。数组下标对应字母,值为最后出现位置。
classSolution{public:vector<int>partitionLabels(string s){intn=s.size();intlast[26];for(inti=0;i<n;i++){last[s[i]-'a']=i;}vector<int>ans;intstart=0,end=0;for(inti=0;i<n;i++){end=max(end,last[s[i]-'a']);if(end==i){ans.push_back(end-start+1);start=end+1;}}returnans;}};输入: s = "ababcbacadefegdehijhklij" 第一步:统计每个字符最后出现的位置 +-------------------------------------------------------------+ | 字符 | a | b | c | d | e | f | h | l | | 最后 | 8 | 9 | 7 | 14 | 15 | 11 | 19 | 22 | +-------------------------------------------------------------+ 第二步:遍历字符串,维护片段边界 +-------------------------------------------------------------+ | i=0 | s[0]='a', end=max(0,8)=8 | end!=i, 继续 | | i=1 | s[1]='b', end=max(8,9)=9 | end!=i, 继续 | | i=2 | s[2]='a', end=max(9,8)=9 | end!=i, 继续 | | i=3 | s[3]='b', end=max(9,9)=9 | end!=i, 继续 | | i=4 | s[4]='c', end=max(9,7)=9 | end!=i, 继续 | | i=5 | s[5]='b', end=max(9,9)=9 | end!=i, 继续 | | i=6 | s[6]='a', end=max(9,8)=9 | end!=i, 继续 | | i=7 | s[7]='c', end=max(9,7)=9 | end!=i, 继续 | | i=8 | s[8]='a', end=max(9,8)=9 | end==i! 切片段 | | | ans.push(8-0+1)=9 | start=9 | +-------------------------------------------------------------+ | i=9 | s[9]='d', end=max(9,14)=14 | end!=i, 继续 | | ... | ... | end!=i, 继续 | | i=15 | s[15]='e', end=max(15,15)=15 | end==i! 切片段 | | | ans.push(15-9+1)=7 | start=16 | +-------------------------------------------------------------+ | i=16 | s[16]='f', end=22 | end!=i, 继续 | | ... | ... | end!=i, 继续 | | i=22 | s[22]='l', end=22 | end==i! 切片段 | | | ans.push(22-16+1)=7? 不对 | 实际是8 | +-------------------------------------------------------------+ 输出: ans = [9, 7, 8]| 复杂度 | 分析 |
|---|---|
| 时间复杂度 | O(n) |
| - 第一遍遍历:O(n) | |
| - 第二遍遍历:O(n) | |
| 空间复杂度 | O(1) |
| - 26 个字母的数组 |
s = "ababcbacadefegdehijhklij" 为什么 end == i 时就能切片段? +-------------------------------------------------------------+ | 位置 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ... | | 字符 a b a b c b a c a d e f e g d e | | 最后 8 9 8 9 7 9 8 7 8 14 15 11 15 14 14 15 ... | +-------------------------------------------------------------+ 在位置 i,如果 end == i,意味着: - 到位置 i 为止,当前片段中的所有字符都已经出现过最后一次了 - 不会再有字符需要跨越 i 才能出现 - 所以位置 i 必须是片段的结束位置 片段 1 分析(位置 0-8): - 包含的字符: a, b, c - a 的最后位置: 8 - b 的最后位置: 9 - c 的最后位置: 7 - 当前 end = max(8,9,7) = 9 - 但位置 8 时,虽然 end=9 != 8,但到了位置 8 之后 - 'a' 的最后位置是 8,就在当前位置,不需要再延伸 - 所以 end == i = 8,切片段!| 思路 | 平均时间 | 最坏时间 | 空间 | 评价 |
|---|---|---|---|---|
| 哈希表 | O(n) | O(n) | O(n) | 可行但稍慢 |
| 数组 | O(n) | O(n) | O(1) | 最优 |
| 问题 | 回答 |
|---|---|
为什么end == i就能切片段? | 因为 end 是当前片段中所有字符最后出现位置的最大值。如果 i == end,说明所有在 [start, i] 范围内的字符都只出现在这个片段里,不会延伸到后面 |
| 为什么要两遍遍历? | 第一遍找每个字符的最后位置,第二遍根据最后位置判断片段边界 |
| 为什么要用数组而不是哈希表? | 26 个字母是固定的,用数组 O(1) 空间,比哈希表更快 |
| 如果字符串为空怎么办? | 返回空 vector |
| 这个算法和区间合并有什么关系? | 本质是把「每个字符的出现区间」合并,合并后的每个区间就是一个片段 |
| 题目 | 难度 | 核心点 |
|---|---|---|
| 763. 划分字母区间 | 中等 | 本题 |
| 56. 合并区间 | 中等 | 区间合并 |
| 435. 无重叠区间 | 中等 | 区间取舍 |
| 项目 | 内容 |
|---|---|
| 核心思想 | 两遍遍历:第一遍记录最后位置,第二遍根据最后位置切片段 |
| 关键判断 | end == i 时切割 |
| 最优时间 | O(n) |
| 最优空间 | O(1) |
| 面试加分 | 能解释「片段内所有字符的最后位置都不会超出片段边界」 |