Algorithm 查找不带'的所有子字符串;不包含整个字符集

Algorithm 查找不带'的所有子字符串;不包含整个字符集,algorithm,language-agnostic,Algorithm,Language Agnostic,这是在一次采访中问我的 我得到了一个字符串,其字符仅来自集合{a,b,c}。查找不包含集合中所有字符的所有子字符串。例如,仅包含a、b、c或仅包含a、b或仅包含b、c或仅包含c、a的子字符串。我通过生成所有子字符串并对其进行测试,给了他天真的O(n^2)解决方案 面试官想要一个O(n)解决方案 编辑:我的尝试是让a、b、c的最后一个索引从左到右运行一个指针,并且每当所有3个都被计数时,更改子字符串的开头以排除最早的一个,然后再次开始计数。这似乎并不详尽 例如,如果字符串是abbcacaa, 让i

这是在一次采访中问我的

我得到了一个字符串,其字符仅来自集合{a,b,c}。查找不包含集合中所有字符的所有子字符串。例如,仅包含a、b、c或仅包含a、b或仅包含b、c或仅包含c、a的子字符串。我通过生成所有子字符串并对其进行测试,给了他天真的O(n^2)解决方案

面试官想要一个O(n)解决方案

编辑:我的尝试是让a、b、c的最后一个索引从左到右运行一个指针,并且每当所有3个都被计数时,更改子字符串的开头以排除最早的一个,然后再次开始计数。这似乎并不详尽

例如,如果字符串是
abbcacaa
, 让
i
作为遍历字符串的指针。让
start
作为子字符串的开始

1) i=0,start=0

2) i=1,开始=0,最后一个索引(a)=0-->1子串-a

3) i=2,开始=0,最后一个索引(a)=0,最后一个索引(b)=1-->1子串ab

4) i=3,开始=0,最后一个索引(a)=0,最后一个索引(b)=2-->1子字符串

5) i=4,start=1,last_index(b)=2,last_index(c)=3-->1子字符串bbc(从子字符串中删除了a)

6) i=5,start=3,last_index(c)=3,last_index(a)=4-->1子字符串ca(从子字符串中删除b)


但这并不是详尽的

为了得到比O(n)更好的结果,我们可能需要额外的假设(可能是具有此属性的最长子字符串)。 考虑字符串“代码> AAAAAAAAAAA,BBBBBBB< <代码>长度n。至少有O(n^2)个可能的子字符串,所以如果我们想列出它们,我们需要O(n^2)个时间

我提出了最长子串的线性解

取一组由
a
分隔的所有子串
S
,由
b
分隔的所有子串,最后是由
c
分隔的所有子串。每个步骤都可以在O(n)中完成,因此我们有O(3n),因此O(n)

示例:
aaabcaacbaa

在这种情况下,集合
S
包含:

  • a
    分隔的子字符串:
    bc
    ccb
  • b
    分隔的子字符串:
    aaa
    caacc
  • c
    分隔的子字符串:
    aaab
    aa
    baa

我所说的集合指的是一个数据结构,在O(1)中添加并查找具有给定键的元素。

鉴于其原始定义中的问题无法在不到O(N^2)的时间内解决,正如一些评论所指出的,我建议使用一种线性算法来计算子字符串的数量(值不一定是唯一的,但在原始字符串中的位置是唯一的)

算法

  • 计数=0
  • 对于{'a'、'b'、'C'}中的每个字符C,扫描输入S并将其分解为不包括C的最长序列。对于每个这样的部分a,添加| a |*(| a |+1)/2进行计数。此加法表示a中合法子字符串的数量
  • 现在我们有了合法字符串的总数,只包括{'a','b'},只包括{'a','c'}和只包含{'b','c'}。问题是,我们用一个重复的字符计算了两次子字符串。为了解决这个问题,我们再次迭代S,这次对我们遇到的单个字符的每个最大序列a减去| a |*(| a |+1)/2
  • 返回计数
  • 示例

    S='aacb'

    使用“a”来打破它只会得到“cb”,所以count=3。对于C='b'我们有'aac',它使count=3+6=9。使用C='C'我们得到'aa'和'b',所以count=9+3+1=13。现在我们必须做减法:'aa':-3,'C':-1,'b':-1。因此我们有了count=8

    这8个子串是:

    'a'
    'a' (the second char this time)
    'aa'
    'ac'
    'aac'
    'cb'
    'c'
    'b'
    

    这是一个一般性的问题,没有指定语言。另外,你是否有任何尝试或想法来解决这个问题?我用C/C++回答,但我认为逻辑是独立于语言的。恐怕问题没有很好的定义。如果输入“a…aba…a”?显然有O(N^2)其中只包含a和b的不同子字符串。这使得运行时间至少为O(N^2)。这是一个技巧性问题:“ab”的输入具有预期的结果[“a”、“b”、“ab]”。因此结果的元素数比输入的元素数多。不可能有O(N)解决方案。顺便说一句,如果问题是计算子字符串的数量,那么这可以根据需要在线性时间内完成。这会导致重复的子字符串。所谓的“集”实际上是指一个集。假设我们将其实现为一个哈希表。“aaa”的“所有子字符串”包含“a”三次。现在它似乎不是O(n)当然,我在最后也考虑了这个集合。谢谢你。我们是如何到达<代码> A(* A + 1)/2 < /代码>子串的数量?@ AK:考虑“A + 1”的位置(介于字符之间,在第一个字符之前和最后一个字符之后)。在A中,选择两个不同的这样的位置会得到一个不同的子字符串,因此子字符串的数量是c(| A |+1,2)=A |*(| A |+1)/2。另一种方法是在A(| A |*(| A |-1)/2)中选择两个不同字符位置的任意组合,然后添加选择单个字符的方法的数量(| A |)。