Leetcode 828. 统计子串中的唯一字符

1.题目描述

我们定义了一个函数 countUniqueChars(s) 来统计字符串 s 中的唯一字符,并返回唯一字符的个数。

例如:s = "LEETCODE" ,则其中 "L", "T","C","O","D" 都是唯一字符,因为它们只出现一次,所以 countUniqueChars(s) = 5

本题将会给你一个字符串 s ,我们需要返回 countUniqueChars(t) 的总和,其中 ts 的子字符串。输入用例保证返回值为 32 位整数。

注意,某些子字符串可能是重复的,但你统计时也必须算上这些重复的子字符串(也就是说,你必须统计 s 的所有子字符串中的唯一字符)。


输入: s = “ABC”
输出: 10
解释: 所有可能的子串为:“A”,“B”,“C”,“AB”,“BC” 和 “ABC”。
其中,每一个子串都由独特字符构成。
所以其长度总和为:1 + 1 + 1 + 2 + 2 + 3 = 10


输入: s = “ABA”
输出: 8
解释: 除了 countUniqueChars(“ABA”) = 1 之外,其余与示例 1 相同。


输入:s = “LEETCODE”
输出:92


提示:

  • 1 <= s.length <= 10^5
  • s 只包含大写英文字符

2.思路分析

2.1 用变化量来思考

  • 所有子串按照其末尾字符的下标分组。
  • 考虑两组相邻的子串:以 s[i-1]结尾的子串、以 s[i]结尾的子串。
  • 以 s[i]结尾的子串,可以看成是以 s[i-1] 结尾的子串,在末尾添加上 s[i]组成。
  • 从左往右遍历 s,考虑将 s[i] 添加到以 s[i-1] 结尾的子串的末尾。添加后,这些以 s[i-1] 结尾的子串的 countUniqueChars 值会如何变化?

在这里插入图片描述

以s=BCADEAFGA 为例,当遍历到最后一个 A 时:

  • A 可以单独作为一个子串,其 countUniqueChars 值为 1;
  • 往子串 G 和 FG 的末尾添加 A,由于 A 不在这些子串中,因此这些子串的 countUniqueChars 值都会增加 1;
  • 往子串 AFG、EAFG 和 DEAFG 的末尾添加 A,由于 A 已经在这些子串中且恰好出现一次,添加后 A 重复出现,因此这些子串的 countUniqueChars 值都会减少 1;
  • 往子串 ADEAFG、CADEAFG 和 BCADEAFG 的末尾添加 A,由于A 已经在这些子串中且不止出现一次,因此添加 A 不会改变这些子串的 countUniqueChars 值。

据此,我们在从左往右遍历 s 的同时,对每个字母 s[i] 记录其上一次出现的下标 last 0 [ s [ i ] ] \textit{last}_0[s[i]] last0[s[i]]上上一次出现的下标 last 1 [ s [ i ] ] \textit{last}_1[s[i]] last1[s[i]]。通过上面的例子,我们可以算出从「以 s[i−1] 结尾的子串」到「以 s[i]] 结尾的子串」,countUniqueChars 值的和,增加/减少了多少:

  • 增加了 i − last 0 [ s [ i ] ] i-\textit{last}_0[s[i]] ilast0[s[i]](注意 s[i] 单独作为一个子串,贡献了 1);
  • _减少了 last 0 [ s [ i ] ] − last 1 [ s [ i ] ] \textit{last}_0[s[i]]-\textit{last}_1[s[i]] last0[s[i]]last1[s[i]]

二者相加,总的变化量为: i − 2 ⋅ l a s t 0 [ s [ i ] ] + l a s t 1 [ s [ i ] ] i−2⋅last_0[s[i]]+last_1[s[i]] i2last0[s[i]]+last1[s[i]]

特别地,如果 last 0 [ s [ i ] ] \textit{last}_0[s[i]] last0[s[i]] last 1 [ s [ i ] ] \textit{last}_1[s[i]] last1[s[i]]不存在,可以视作 −1,从而保证上式的正确性。

3.代码实现

3.1 用变化量来思考

class Solution:
    def uniqueLetterString(self, s: str) -> int:
        result = total = 0
        last0, last1 = {}, {}
        for i, c in enumerate(s):
            total += i - 2 * last0.get(c, -1) + last1.get(c, -1)
            result += total
            last1[c] = last0.get(c, -1)
            last0[c] = i
        return result

复杂度分析
时间复杂度:O(n),其中 n 为 s 的长度。
空间复杂度: O ( ∣ Σ ∣ ) O(|\Sigma|) O(∣Σ∣),其中 ∣ Σ ∣ |\Sigma| ∣Σ∣ 为字符集合的大小,本题中字符均为大写字母,所以 ∣ Σ ∣ |\Sigma| ∣Σ∣=26。

参考:
1.https://leetcode.cn/problems/count-unique-characters-of-all-substrings-of-a-given-string/solution/by-muse-77-v7cs/
2.https://leetcode.cn/problems/count-unique-characters-of-all-substrings-of-a-given-string/solution/by-endlesscheng-ko4z/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值