【问题标题】:Number of substrings of a given string containing a specific character包含特定字符的给定字符串的子字符串数
【发布时间】:2019-04-11 14:14:45
【问题描述】:

计算给定字符串中包含给定字符的子字符串数量的最有效算法是什么。

例如对于abb b

子字符串:a、b、b、ab、bb、abb。 答案:包含 b 的字符串至少一次 = 5。

PS。我通过生成所有子字符串然后签入 O(n ^ 2) 解决了这个问题。只是想知道是否有更好的解决方案。

【问题讨论】:

  • 在 Python 中试试这个re.findall(r"(?=(?P<sub>.*b+))", "abb"),首先是import re

标签: algorithm data-structures


【解决方案1】:

让你需要找到带有字符 X 的子字符串。

从左到右扫描字符串,保持最后一个 X 的位置:lastX 与起始值 -1

当您在位置 i 遇到 X 时,将 i+1 添加到结果并更新 lastX
(这是以当前位置结尾的子字符串的数量,它们都包含 X)

遇到其他角色时,在结果中添加lastX + 1
(这又是以当前位置结尾并包含 X 的子字符串的数量),
因为子字符串的最右边可能的开始是最后一个 X 的位置

算法是线性的。
示例:

a X a a X a
            good substrings                            overall     
idx  char   ending at idx             lastX   count    count
 0    a      -                        -1       0        0  
 1    X     aX X                       1       2        2 
 2    a     aXa Xa                     1       2        4
 3    a     aXaa Xaa                   1       2        6 
 4    X     aXaaX XaaX aaX aX X        4       5        11 
 5    a     aXaaXa XaaXa aaXa aXa Xa   4       5        16 

Python 代码:

def subcnt(s, c):
    last = -1
    cnt = 0
    for i in range(len(s)):
        if s[i] == c:
            last = i
        cnt += last + 1
    return cnt

print(subcnt('abcdba', 'b'))

【讨论】:

  • 澄清一下:对于第一种情况,我会写“在当前位置结束,它们都包含 X”,对于第二种情况,“在当前位置结束并包含 X - 这与所有子字符串完全对应包含位置 lastX 并以当前位置结束的字符"
  • 在遇到第一个“x”后,我不明白子字符串的计数方式。即在索引 2 、 3 和 4 下
  • 子字符串的最后一个可能开始是最后一个 X 的位置。参见增强示例
【解决方案2】:

您可以将其翻转并扫描您的字符串以查找您的字母。每次在i 的某个位置找到一个事件时,您就知道它包含在包含它的所有子字符串中(即,所有子字符串在i 之前或之后,在i 或之后结束),所以你只需要存储索引对来定义子字符串,而不是显式存储子字符串。

话虽如此,您仍然需要 O(n²) 使用这种方法,因为尽管您不介意重复的子字符串,如示例所示,但您不想计算相同的子字符串两次,因此您仍然必须确保不要两次选择同一对索引。

【讨论】:

    【解决方案3】:

    让我们将字符串视为abcdaefgabb,将给定字符视为a

    • 按字符循环遍历字符串。
    • 如果一个字符与给定字符匹配,假设索引为4 处的a,那么包含a 的子字符串的数量是从abcdaaefgabb。所以,我们添加(4-0 + 1) + (10 - 4) = 11。这些表示子串为abcda,bcda,cda,da,a,ae,aef,aefg,aefga,aefgab0@和aefgab。李>
    • 这适用于您找到a 的任何位置,就像您在索引0 和索引8 中找到它一样。
    • 最终答案是上述数学运算的sum

    更新:您必须在上次发生的a 和当前的a 之间维护 2 个指针,以避免计算以相同索引开始结束的重复子字符串。

    【讨论】:

      【解决方案4】:

      将子字符串视为从字符串中字母之间的间隙中选择两个元素,并包括它们之间的所有内容(字符串的末端有间隙)。

      对于长度为n的字符串,有choose(n+1,2)个子字符串。

      其中,对于不包含目标的 k 个字符的每一次运行,都有一个 choose(k+1,2) 个子字符串,其中仅包含该子字符串中的字母。主字符串的所有其他子字符串必须包含目标。

      答案:choose(n+1,2) - sum(choose(k_i+1,2)),其中 k_i 是不包括目标的字母的运行长度。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-05-15
        • 2011-03-18
        • 1970-01-01
        • 1970-01-01
        • 2021-10-23
        • 1970-01-01
        • 1970-01-01
        • 2023-03-24
        相关资源
        最近更新 更多