【问题标题】:Naive String Search Algorithm - Python朴素字符串搜索算法 - Python
【发布时间】:2016-12-17 13:26:58
【问题描述】:

我已经实现了下面的朴素字符串搜索算法('find')。它尽可能简单。然而,我在“GeeksforGeeks”('search') 上找到了另一种方法,它看起来具有更好的复杂性。当我对大字符串进行测试时,结果截然不同但相反。

1st:将字符串切成模式长度并进行比较。向前移动一个字符切片并进行比较。这应该是什么复杂性?

def find(pat, txt):
    size = len(pat)
    for i in range( len(txt) -size + 1 ):
        if txt[i : i + size] == pat:
            print 'Pattern found at index %s'%(i)

2nd:逐个字符比较。如果一个字符不匹配中断。否则继续。最后,如果所有字符匹配打印结果。向前移动一个字符。这应该是什么复杂性?

def search(pat, txt):
    M = len(pat)
    N = len(txt)

    for i in xrange(N-M+1):
        status = 1 
        for j in xrange(M):
            if txt[i+j] != pat[j]:
                status = 0
                break
        if j == M-1 and status != 0:
            print "Pattern found at index " + str(i)

时序测试用例:

testString = ''.join([ 'a' for _ in range(1000*100)] ) + 'b'
testPattern = ''.join([ 'a' for _ in range(100*100) ])  + 'b'

import cProfile
cProfile.run('find(testPattern, testString)')
cProfile.run('search(testPattern, testString)')

find

Pattern found at index 90000
         90007 function calls in 0.160 seconds

对于search

Pattern found at index 90000
         5 function calls in 135.951 seconds

在我的算法find 中,我进行切片和比较。切片的时间复杂度是 O(k),类似地为了比较它应该需要另一个 O(k) 虽然不确定。 Python Time Complexity

search 中,我们只运行了“k”次循环。所以它不应该有更好的时间复杂度。

【问题讨论】:

  • 算法 A 在给定测试中的表现是否优于算法 B,以及算法 A 的时间复杂度是否优于算法 B,这是两个独立的问题。一方面——复杂性结果是渐近的。另一方面,big-O 表示法中的比例常数可以隐藏大量的低效率。我不知道这里发生了什么——但你似乎在比较苹果和橘子。
  • @JohnColeman 但我们总是可以谈论最坏的情况。我尝试使用不同的字符串。但总的来说,第一种算法更快,而且也有很大的不同。我试图了解我在哪里出错了。假设只是针对这种情况,为什么会出现这些结果?
  • 您可以对此进行分析并找出,查找标准的 python 分析工具。我没有看到这两种算法之间的实质性区别,但是,您的实现依赖于运行时完成的本机字符串比较,另一个实现在纯 python 中逐个字符地进行比较。这要慢得多。
  • 在 Python 中,算法上“较慢”的方法比在解释代码中实现的算法上“较快”的算法更好地利用内置方法(在优化的编译 C 中运行)执行更好的算法并不少见。这是可以隐藏在比例常数中的低效率之一。
  • 第二种方法是原生字符串比较在 Python 中的工作方式。如果第一个字符不匹配,则无需查看其余字符。不同之处在于它以更优化的方式实现。

标签: python string algorithm


【解决方案1】:

您的两种算法本质上是相同的(正如@Zah 指出的那样),唯一的区别是第二种算法中的内部循环是由第一种算法中的底层 C 代码完成的。您正在观察的是编译代码和解释代码之间的区别。

如果您想要所有索引并想利用内置方法:

def findAll(s,t):
    """returns all indices where substring t occurs in string s"""
    indices = []
    i = s.find(t)
    while i > -1:
        indices.append(i)
        i = s.find(t,i+1)
    return indices

例如,

>>> findAll("The cat in the hat","at")
[5, 16]

【讨论】:

  • 所以我最好在“竞争性编程”中使用本机方法,而不是尝试编写自己的字符串搜索?
  • cool :) 这比我的实现要快得多。 Python 本机 find 使用 Bayers Moore 并在顶部添加了一些花里胡哨的功能。所以我认为我最好总是使用它。
  • @garg10 可能是编程竞赛意义上的“竞争性编程”,可能会有关于什么是允许的和不被允许的规则,这些规则可能在不同的比赛之间有所不同。如果您只关心效率——使用内置方法的 Python 代码比仅使用循环和索引的逻辑等效代码更快。
【解决方案2】:

我在 PYTHON 中实现了朴素的搜索代码,简单理解如下。 它将返回没有找到时间模式。

def naive_pattern_search(data,search):
n = len(data) #Finding length of data
m = len(search) #Finding length of pattern to be searched.

i = 0
count = c = 0 #Taking for counting pattern if exixts.
for j in range(m-1):#Loop continue till length of pattern to be Search.
    while i <= (n-1):#Data loop
        
        #if searched patten length reached highest index at that time again initilize with 0.
        if j > (m-1):
            j = 0
        
        #Data and search have same element then both Index increment by 1.
        if data[i]==search[j]:
            #print(f"\n{ data[i] } { search[j] }")
            #print(f"i : {i}  {data[i]}   j : {j}  {search[j]}")
            i+=1
            j+=1
            count+=1
            
            #If one pattern compared and found Successfully then Its Counter for pattern.
            if count== (m-1):
                c = c + 1
        #Initilise pattern again with 0 for searching with next element in data.
        else:
            j = 0 #Direct move to 0th index.
            i+=1
            count=0 #If data not found as per pattern continuously then it will start counting from 0 again.

#Searched pattern occurs more then 0 then its Simply means that pattern found.
if c > 0:
    return c;
else:
    return -1;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-11-29
    • 2012-01-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多