📌  相关文章
📜  计算具有不同首尾字符的子串(1)

📅  最后修改于: 2023-12-03 15:41:37.842000             🧑  作者: Mango

计算具有不同首尾字符的子串

在字符串处理中,我们经常需要计算一个字符串中具有不同首尾字符的子串个数。例如,对于字符串 "abccddefgfhij",其具有不同首尾字符的子串有 "ab", "ac", "ad", "ae", "af", "ag", "ah", "ai", "bc", "bd", "be", "bf", "bg", "bh", "bi", "cd", "ce", "cf", "cg", "ch", "ci", "dd", "de", "df", "dg", "dh", "di", "ee", "ef", "eg", "eh", "ei", "ff", "fg", "fh", "fi", "gg", "gh", "gi", "hh", "hi", "ii" 共 $45$ 个。

本文将介绍两种常见的计算方法:暴力枚举和哈希表。

暴力枚举法

暴力枚举法是比较 naive 但也是最常见的解法。我们可以遍历字符串中每一个字符,然后依次枚举以该字符为首的子串,最后计算出具有不同首尾字符的子串个数。

def count_substrings(s: str) -> int:
    ans = 0
    for i in range(len(s)):
        for j in range(i + 1, len(s)):
            if s[i] != s[j]:
                ans += 1
    return ans

时间复杂度:$O(n^2)$,其中 $n$ 是字符串的长度。

哈希表法

暴力枚举法的时间复杂度太高,在面对大规模数据时,容易出现超时等问题。因此,我们需要寻找一个更高效的方法。

考虑用哈希表存储每个字符在字符串中最后出现的下标。对于字符串中的每个字符 $c_i$,我们只需要在哈希表中查找下标 $j$,使得 $i+1 \le j \le n$ 且 $c_j \neq c_i$。然后统计不同首尾字符的子串个数即可。

def count_substrings(s: str) -> int:
    n = len(s)
    last = {}
    ans = 0
    for i in range(n):
        for j in range(ord('a'), ord('z') + 1):
            if chr(j) in last and s[i] != chr(j):
                k = last[chr(j)]
                if k > i:
                    ans += 1
        last[s[i]] = i
    return ans

代码中,我们使用字典(Python 中的哈希表)来存储每个字符最后出现的下标。对于每个字符 $c_i$,我们枚举所有不同于 $c_i$ 的字符 $c_j$,然后在字典中查找 $c_j$ 最后一次出现的下标 $k$,如果 $k > i$,则说明 $c_i$ 和 $c_j$ 分别作为首尾字符的子串的个数。

时间复杂度:$O(n \cdot \sigma)$,其中 $\sigma$ 是字符集的大小。

总结

本文介绍了如何计算具有不同首尾字符的子串个数,分别使用了暴力枚举法和哈希表法。暴力枚举法时间复杂度较高,只适用于小规模数据;哈希表法时间复杂度较低,适用于大规模数据。