繁体   English   中英

检查组合字符串中子串顺序的算法

[英]Algorithm to check the order of substrings in combined string

问题如下:如果有两个字符串str1str2 ,另一个字符串str3 ,写一个函数,检查str3是否包含str1的字母和str2的字母,它们的顺序与原始序列中的字母相同,虽然它们可能是交错的。 因此,对于子串adfbecadbfec返回true。 我在Python中编写了以下函数:

def isinter(str1,str2,str3):
    p1,p2,p3 = 0,0,0
    while p3 < len(str3):
        if p1 < len(str1) and str3[p3] == str1[p1]:
            p1 += 1
        elif p2 < len(str2) and str3[p3] == str2[p2]:
            p2 += 1
        else:
            break
        p3 = p1+p2
    return p3 == len(str3)

这个程序的另一个版本是在ardentart (最后一个解决方案)。 现在哪一个更好? 我想我的,因为它可能在线性时间内完成。 无论是否更好,我的算法还有进一步优化的空间吗?

不幸的是,你的版本不起作用。 想象一下输入abacacab 您的算法返回False ,这是不正确的。

问题是当str3看到的字母可以str3解释时,你总是走str1 ; 步行可能需要str2 ,但它与您的算法没有相同的机会。

接近它的另一种方法是使用python的regex模块。 您可以拆分str1的字符,并用。*包围每个字符以匹配它们之间的任何数字(或无)字符。 这将为您提供匹配str1的模式。 然后对str2执行相同操作,然后只运行re.match(str1pattern,str3)和re.match(str2pattern,str3)。 如果它们都返回对象(即除了None之外的任何东西),那么你就可以匹配两个字符串。

这可能会更好地扩展,因为它更容易添加更多字符串来检查,如果你需要更好的性能来搜索各种其他字符串,那么你也可以编译模式。

您可以拆分列表中的所有三个字符串:

list1 = list(str1)

然后使用您现在使用的相同算法遍历list3 ,检查list3[i]是否等于list1[0]list2[0] 如果是,您可以从相应的列表中del该项目。

然后可以将过早的列表结束作为例外捕获。

算法完全相同,但实现应该更高效。

更新 :事实证明它实际上不是(大约两倍的时间)。 哦,好吧,知道可能有用。

在对不同场景进行基准测试时,结果发现除非指定三个字符串长度是“精确”(即len(p1)+ len(p2)== len(p3)),否则最有效的优化是检查第一件事。 由于字符串长度不正确 ,这会立即丢弃两个输入字符串与第三个输入字符串匹配的所有情况。

然后我遇到一些情况,两个字符串中都有相同的字母,并将其分配给list1或list2可能会导致其中一个字符串不再匹配。 在这些情况下,算法失败并出现假阴性,这需要递归。

def isinter(str1,str2,str3,check=True):
    # print "Checking %s %s and %s" % (str1, str2, str3)
    p1,p2,p3 = 0,0,0
    if check:
        if len(str1)+len(str2) != len(str3):
            return False
    while p3 < len(str3):
        if p1 < len(str1) and str3[p3] == str1[p1]:
            if p2 < len(str2) and str3[p3] == str2[p2]:
                # does str3[p3] belong to str1 or str2?
                if True == isinter(str1[p1+1:], str2[p2:], str3[p3+1:], False):
                   return True
                if True == isinter(str1[p1:], str2[p2+1:], str3[p3+1:], False):
                   return True
                return False
            p1 += 1
        elif p2 < len(str2) and str3[p3] == str2[p2]:
            p2 += 1
        else:
            return False
        p3 += 1
    return p1 == len(str1) and p2 == len(str2) and p3 == len(str3)

然后我在随机字符串上运行了一些基准测试,这是仪器( 注意它生成的总是有效的 shuffle,这可能会产生偏差的结果 ):

for j in range(3, 50):
        str1 = ''
        str2 = ''
        for k in range(1, j):
                if random.choice([True, False]):
                        str1 += chr(random.randint(97, 122))
                if random.choice([True, False]):
                        str2 += chr(random.randint(97, 122))
        p1 = 0
        p2 = 0
        str3 = ''
        while len(str3) < len(str1)+len(str2):
                if p1 < len(str1) and random.choice([True, False]):
                        str3 += str1[p1]
                        p1 += 1
                if p2 < len(str2) and random.choice([True, False]):
                        str3 += str2[p2]
                        p2 += 1
        a = time.time()
        for i in range(1000000):
                isShuffle2(str1, str2, str3)
        a = (time.time() - a)
        b = time.time()
        for i in range(1000000):
                isinter(str1, str2, str3)
        b = (time.time() - b)

        print "(%s,%s = %s) in %f against %f us" % (str1, str2, str3, a, b)

结果似乎表明缓存+ DP算法对字符串的优越效率。 当字符串变长(超过3-4个字符)时,缓存+ DP算法开始失去理由。 在大约10长度,上面的算法执行的速度是完全递归的缓存版本的两倍。

如果字符串包含重复字符(我通过将范围从az限制为ai)并且重叠是轻微的,则DP算法执行得更好,但仍然比上述更差。 例如,在这种情况下,DP仅损失2us:

(cfccha,ddehhg = cfcchaddehhg) in 68.139601 against 66.826320 us

毫不奇怪,完全重叠(每个字符串依次为一个字母)看到较大的差异,比率高达364:178(略大于2:1)。

首先,只是一个实现点:我认为你可以摆脱对str1和str2长度的测试。 在C中,字符串以nul字符终止,因此在str3中永远不会找到此特殊字符。 所以如果找到正确的字符,只需输入p1++ 但是在python中我不记得这个功能是不是...抱歉,我不是一个严肃的python用户。 如果p1 == len(p1),str1 [p1]的输出是多少?

除此之外,正如Jirka Hanika所指出的,您的代码输出是错误的。 我已经看到了另一种失败的情况:如果一个字符与两个子字符串相同。 例如:如果str1 =“abc”,str2 =“dbe”,则str3 =“adbec”包含str1和str2,但您的算法在这种情况下失败。 问题来自elif语句,而是另外一个if。

Iserni的代码输出在我看来是正确的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM