Skip to content

题目链接 · 灵神原题解(署名来源)

思路

「同一字母最多出现在一个片段中」意味着,一个片段若要包含字母 a,那么所有的字母 a 都必须在这个片段中。

示例 1 的 s=ababcbacadefegdehijhklij,其中字母 a 出现在下标 0,2,6,8 上,那么包含 a 的片段至少要包含区间 [0,8]

把所有出现在 s 中的字母及其下标区间列出来:

字母下标下标区间
a0,2,6,8[0,8]
b1,3,5[1,5]
c4,7[4,7]
d9,14[9,14]
e10,12,15[10,15]
f11[11,11]
g13[13,13]
h16,19[16,19]
i17,22[17,22]
j18,23[18,23]
k20[20,20]
l21[21,21]

例如字母 d 的区间为 [9,14],片段要包含 d,必须包含区间 [9,14],但区间 [9,14] 中还有其它字母 e,f,g,所以该片段也必须包含这些字母对应的区间 [10,15],[11,11],[13,13],合并后得到区间 [9,15]

将表格中的区间合并为如下几个大区间:

[0,8],[9,15],[16,23]

这些区间满足「同一字母最多出现在一个片段中」的要求,区间长度分别为 9,7,8

由于题目要求划分出尽量多的片段,而我们又无法将上述区间的任何区间划分开,所以合并后的区间长度即为答案。

算法

  1. 遍历 s,计算字母 cs 中的最后出现的下标 last[c]
  2. 初始化当前正在合并的区间左右端点 start=0, end=0
  3. 再次遍历 s,由于当前区间必须包含所有 s[i],所以用 last[s[i]] 更新区间右端点 end 的最大值。
  4. 如果发现 end=i,那么当前区间合并完毕,把区间长度 endstart+1 加入答案。然后更新 start=end+1 作为下一个区间的左端点。
  5. 遍历完毕,返回答案。
python
class Solution:
    def partitionLabels(self, s: str) -> List[int]:
        last = {c: i for i, c in enumerate(s)}  # 每个字母最后出现的下标
        ans = []
        start = end = 0
        for i, c in enumerate(s):
            end = max(end, last[c])  # 更新当前区间右端点的最大值
            if end == i:  # 当前区间合并完毕
                ans.append(end - start + 1)  # 区间长度加入答案
                start = end + 1  # 下一个区间的左端点
        return ans
cpp
// C++ 版待补充
cpp
class Solution {
public:
    vector<int> partitionLabels(string s) {
        int n = s.size();
        int last[26];
        for (int i = 0; i < n; i++) {
            last[s[i] - 'a'] = i; // 每个字母最后出现的下标
        }

        vector<int> ans;
        int start = 0, end = 0;
        for (int i = 0; i < n; i++) {
            end = max(end, last[s[i] - 'a']); // 更新当前区间右端点的最大值
            if (end == i) { // 当前区间合并完毕
                ans.push_back(end - start + 1); // 区间长度加入答案
                start = end + 1; // 下一个区间的左端点
            }
        }
        return ans;
    }
};

复杂度分析

  • 时间复杂度:O(n),其中 ns 的长度。
  • 空间复杂度:O(|Σ|)。其中 |Σ| 是字符集合的大小,本题字符均为小写字母,所以 |Σ|=26

相似题目

更多相似题目,见下面贪心题单中的「§2.5 合并区间」。

分类题单

如何科学刷题?

  1. 滑动窗口与双指针(定长/不定长/单序列/双序列/三指针/分组循环)
  2. 二分算法(二分答案/最小化最大值/最大化最小值/第K小)
  3. 单调栈(基础/矩形面积/贡献法/最小字典序)
  4. 网格图(DFS/BFS/综合应用)
  5. 位运算(基础/性质/拆位/试填/恒等式/思维)
  6. 图论算法(DFS/BFS/拓扑排序/基环树/最短路/最小生成树/网络流)
  7. 动态规划(入门/背包/划分/状态机/区间/状压/数位/数据结构优化/树形/博弈/概率期望)
  8. 常用数据结构(前缀和/差分/栈/队列/堆/字典树/并查集/树状数组/线段树)
  9. 数学算法(数论/组合/概率期望/博弈/计算几何/随机算法)
  10. 贪心与思维(基本贪心策略/反悔/区间/字典序/数学/思维/脑筋急转弯/构造)
  11. 链表、树与回溯(前后指针/快慢指针/DFS/BFS/直径/LCA)
  12. 字符串(KMP/Z函数/Manacher/字符串哈希/AC自动机/后缀数组/子序列自动机)

我的题解精选(已分类)

欢迎关注 B站@灵茶山艾府

本文整理自灵茶山艾府(endlesscheng)的公开内容,仅供个人学习使用

本站仅供个人学习使用,请勿外传