在刷题中过年 1930 ~ 长度为 3 的不重复 substring
基本信息
- 题号:1930
 - 题厂:亚麻,脸书,谷歌
 - 难度系数:中
 
找出一个字符串中所有不重复、长度为 3 的 palindromic substring 字符串个数。。。
- palindromic:即对称的字符串,例如 aba,bab。。。
 - subsequence:比原数组短,但是保持顺序一致。。。如 abcc 是 aabbcccc 的 subsequence
 
s = "aabca" 返回 3 长度为 3 满足 subsequence palindromic 标准的有 aba,aaa,aca
解题思路
- 要找 palindromic,一个比较常规的方法思路是,以一个元素为中心,向左右两边扩散。。。。这样比较麻烦。。。。
 - 关于这道题,要抓住题目只找长度为 3 的 palindromic。abba 虽然也是 palindromic,但是长度为 4 所以不需要。
 - 既然是长度为 3,那必然满足一个 pattern,那就是左右字符相同,中间随意。
 - 沿着以上思路,我们以一个字符为中心,如果它的左右分别有相同的字符出现,即可满足条件。。。。。想到这里可以明白,此处需要使用 set。。。。。。
 
class Solution:
    def countPalindromicSubsequence(self, s: str) -> int:
        # 初始化 res 用于返回,元素配对模式为 「中间元素:两边元素」
        res = set() 
        # 同时初始化左右 set,右边用 hashmap 记录,配对模式为 「元素:个数」
        left = set()
        right = collections.Counter(s) # generate hashmap
        
        # 遍历数组,如果当前元素在右边 hashmap 中,hashmap 对应元素所剩数量减 1;如果剩余数量为 0,就把该元素从 hashmap 中 pop 出去
        for i in range(len(s)):
            if s[i] in right:
                right[s[i]] -= 1
            
            if right[s[i]] == 0:
                right.pop(s[i])
            # 左右两边如何检测??采用处理字符串中常用 ascii 方面
            # 如果我们在左右 set 中都找到了相同元素,则发现了一个「长度为 3 又是 palindromic 的 subsequence」,需要往 res 里添加
            for j in range(26):
                c = chr(ord("a") + j)
                if c in left and c in right:
                    res.add((s[i], c))
            # 添加完 还要把当前元素加到左边 set,以便下一次遍历
            left.add(s[i])
        # 返回 res 的长度,即满足所有条件又不重复的数量。。。。
        return len(res)
Constraints
3 <= s.length <= 105s consists of only lowercase English letters.
做题前要向考官讨论字符串包括什么特色,字符串只有 26 个小写英文字母出现是可以使用 ascii 码解体的重点。。。。。。
测试
- 长度为 3 没有了 palindromic 时
 - 长度为 3 有 pandlindromic 时
 - 长度大于 3 有很多重复字符时
 - ……
 
Big O
时间复杂度:O(26n)- 空间复杂度:O(n)
 
总结
- 简化时间复杂度的关键在于要抓住题目特色:长度为 3, 元素只有 26 个小写英文字符……
 - palindromic 是字符串,数组问题常考高频话题,各种变形……
 
