如果我有一个长度为n的字符串S和一个元组列表(a,b),其中a指定S子串的起始位置,b是子串的长度.为了检查是否有任何子串重叠,我们可以在触摸时标记S中的位置.但是,如果元组列表的大小为n(循环元组列表,然后循环S),我认为这将花费O(n ^ 2)时间.
是否有可能在O(n)时间内检查是否有任何子串实际上与另一个子串重叠?
编辑:
例如,S =“abcde”.元组= [(1,2),(3,3),(4,2)],表示“ab”,“cde”和“de”.我想知道在读取(4,2)时发现重叠.
我认为它是O(n ^ 2)因为你每次都得到一个元组,然后你需要遍历S中的子字符串以查看是否有任何字符被标记为脏.
编辑2:
一旦检测到碰撞,我就无法退出.想象一下,我需要报告所有碰撞的后续元组,所以我必须遍历整个元组列表.
编辑3:
算法的高级视图:
for each tuple (a,b)
for (int i=a; i <= a+b; i++)
if S[i] is dirty
then report tuple and break //break inner loop only
最佳答案 您的基本方法是正确的,但您可以优化您的停止条件,以确保在最坏的情况下有限的复杂性.以这种方式思考 – 在最坏的情况下,你需要在S中有多少个位置进行遍历和标记?
如果没有碰撞,那么在最坏的情况下你会访问长度(S)位置(到那时用完元组,因为任何额外的元组都必须碰撞).如果发生碰撞 – 您可以停在第一个标记的对象上,所以再次受到未标记元素的最大数量的限制,即长度(S)
编辑:既然你添加了报告所有碰撞元组的要求,让我们再次计算(扩展我的评论) –
标记所有元素后,您可以通过单个步骤(O(1))检测每个其他元组的碰撞,因此您需要O(n n)= O(n).
这一次,每个步骤要么标记一个未标记的元素(在最坏的情况下为总体n),要么标识一个碰撞的元组(我们假设的最差的O(元组)也是n).
实际步骤可以是交错的,因为元组可以以任何方式组织而不首先发生碰撞,但是一旦它们发生(在最多n个元素之后覆盖所有n个元素之后第一次发生碰撞),你必须每次碰撞第一步.其他安排可能会在标记所有元素之前更早发生碰撞,但是再次 – 您只是重新安排相同数量的步骤.
最糟糕的情况示例:一个元组覆盖整个数组,然后是n-1个元组(无关紧要) –
[(1,n),(n,1),(n-1,1),…(1,1)]
第一个元组将采用n个步骤来标记所有元素,其余的将采用每个O(1)来完成.总体O(2n)= O(n).现在说服自己以下示例采用相同数量的步骤 –
[(1,n / 2-1),(1,1),(2,1),(3,1),(n / 2,n / 2),(4,1),(5,1) ……第(n,1)]