一尘不染

字符串2的字谜是字符串1的子字符串

algorithm

如何找到字符串1的任何字谜是字符串2的子字符串?

例如:-

弦1 = 摇摆

字符串2 = stackoverflow

因此它将返回true,因为“ rove”的字谜是“ over”,这是字符串2的子字符串


阅读 214

收藏
2020-07-28

共1个答案

一尘不染

编辑时:在最坏的情况下,我的第一个答案是二次方。我将其调整为严格线性的:

这是一种基于滑动窗口概念的方法:创建一个字典,该字典由第一个字典的字母作为键,并带有对应值的字母频率计数。可以将其视为目标字典,m第二个字符串中的连续字母需要匹配,其中m第一个字符串的长度是。

首先处理m第二个字符串中的第一个字母。对于每个这样的字母,如果它在目标字典中作为键出现,则将其对应的值 减小
1。目标是将所有目标值驱动为0。定义discrepancy为在处理完第一个窗口后的值的绝对值之和。m字母。

重复执行以下操作:检查是否discrepancy == 0返回True。否则-将字符m字母放在前面,并检查它是否为目标键,如果是-
将值增加1。在这种情况下,这会将差异增加或减少1,并进行相应调整。然后获取第二个字符串的下一个字符并进行处理。检查它是否是字典中的键,如果合适,请适当调整值和差异。

由于没有嵌套循环,并且每次通过主循环都只涉及几个字典查找,比较,加法和减法,因此整个算法是线性的。

Python 3实现(显示了窗口如何滑动以及调整目标计数和差异的基本逻辑):

def subAnagram(s1,s2):
    m = len(s1)
    n = len(s2)
    if m > n: return false
    target = dict.fromkeys(s1,0)
    for c in s1: target[c] += 1

    #process initial window
    for i in range(m):
        c = s2[i]
        if c in target:
            target[c] -= 1
    discrepancy = sum(abs(target[c]) for c in target)

    #repeatedly check then slide:
    for i in range(m,n):
        if discrepancy == 0:
            return True
        else:
            #first process letter from m steps ago from s2
            c = s2[i-m]
            if c in target:
                target[c] += 1
                if target[c] > 0: #just made things worse
                    discrepancy +=1
                else:
                    discrepancy -=1
            #now process new letter:
            c = s2[i]
            if c in target:
                target[c] -= 1
                if target[c] < 0: #just made things worse
                    discrepancy += 1
                else:
                    discrepancy -=1
    #if you get to this stage:
    return discrepancy == 0

典型输出:

>>> subAnagram("rove", "stack overflow")
True
>>> subAnagram("rowe", "stack overflow")
False

为了对其进行压力测试,我从Gutenberg项目下载了Moby
Dick的
全文。它有超过一百万个字符。书中提到“福尔摩沙”,因此“摩尔人”的字谜出现在白鲸的子串中。但是,毫不奇怪,在Moby
Dick中没有出现“ stackoverflow”的字谜:

>>> f = open("moby dick.txt")
>>> md = f.read()
>>> f.close()
>>> len(md)
1235186
>>> subAnagram("moors",md)
True
>>> subAnagram("stackoverflow",md)
False

最后一次调用大约需要1秒钟来处理Moby Dick的完整文本,并验证其中没有出现“ stackoverflow”字谜。

2020-07-28