在大海捞针找到针,什么是更好的解决方案?

时间:2015-04-22 23:36:57

标签: python dynamic-programming

所以给了“针”和“这里有针但不是这个针干草堆”

我写了

def find_needle(n,h):
    count = 0
    words = h.split(" ")
    for word in words:
        if word == n:
            count += 1
    return count

这是O(n),但想知道是否有更好的方法?也许根本不使用拆分?

如何为此案例编写测试以检查它是否处理所有边缘情况?

8 个答案:

答案 0 :(得分:9)

我认为这可能与O(n)相反(因为你需要至少迭代一次字符串)。你可以做一些优化。

我假设您要匹配" 整个单词",例如查找foo应该匹配如下:

foo and foo, or foobar and not foo.
^^^     ^^^                    ^^^

仅仅基于太空的夹板不会起作用,因为:

>>> 'foo and foo, or foobar and not foo.'.split(' ')
['foo', 'and', 'foo,', 'or', 'foobar', 'and', 'not', 'foo.']
#                  ^                                     ^

这是re module派上用场的地方,可以让你建立迷人的条件。例如,正则表达式中的\b表示:

  

匹配空字符串,但仅匹配单词的开头或结尾。 单词被定义为Unicode字母数字或下划线字符的序列,因此单词的结尾由空格或非字母数字 ,非下划线Unicode字符表示。请注意,正式地,\b被定义为\w\W字符之间的边界(反之亦然),或\w与字符串的开头/结尾之间的边界。这意味着r'\bfoo\b'匹配'foo''foo.''(foo)''bar foo baz'但不匹配'foobar''foo3'

因此r'\bfoo\b'仅匹配整个字foo 。也不要忘记使用re.escape()

>>> re.escape('foo.bar+')
'foo\\.bar\\+'
>>> r'\b{}\b'.format(re.escape('foo.bar+'))
'\\bfoo\\.bar\\+\\b'

现在您只需使用re.finditer()扫描字符串即可。基于文档:

  

返回一个迭代器,在字符串中的RE模式的所有非重叠匹配上产生匹配对象。从左到右扫描字符串,并按找到的顺序返回匹配项。结果中包含空匹配,除非它们触及另一场比赛的开头。

我认为匹配是动态生成的 ,所以它们不必一次在内存中(这可能会与字符串派上用场,许多匹配项目)。最后只计算它们:

>>> r = re.compile(r'\bfoo\b')
>>> it = r.finditer('foo and foo, or foobar and not foo.')
>>> sum(1 for _ in it)
3

答案 1 :(得分:5)

这并未解决复杂性问题,但简化了代码:

def find_needle(n,h):
    return h.split().count(n)

答案 2 :(得分:4)

您可以使用Counter

from collections import Counter

def find_needle(n,h):
    return Counter(h.split())[n]

即:

n = "portugal"
h = 'lobito programmer from portugal hello fromportugal portugal'

print find_needle(n,h)

输出:

2

DEMO

答案 3 :(得分:3)

实际上,当你说O(n)你忘记了匹配第一个字母后,你必须匹配剩余的那个(从针到句子匹配n,然后匹配e,然后是下一个e。 ..)您实际上是在尝试复制grep的功能,因此您可以查看grep算法。你可以通过构建有限状态机来做得很好。有许多链接可以帮助您,您可以从How does grep run so fast?

开始

答案 4 :(得分:1)

这仍然是O(n),但它使用了re模块和python的生成器表达式的强大功能。

import re

def find_needle(n,h):
    g = re.finditer(r'\b%s\b'%n, h)  # use regex word boundaries
    return sum(1 for _ in g)  # return the length of the iterator

对于相对较大的“干草堆”,应该使用比.split少得多的内存。

请注意,这与OP中的代码并不完全相同,因为它不仅会找到' needle'还有针,'并且'针。'它找不到针头'虽然。

答案 5 :(得分:0)

为了保证在大海捞针中找到针,你需要检查每一块干草,直到找到针。无论如何,这都是O(n),一个紧张的下限。

答案 6 :(得分:0)

def find_needle(haystack):
    for item in haystack:
        if item  == 'needle':
            haystack.append(item)
            return 'found the needle at position ' + str(haystack.index(item))

答案 7 :(得分:0)

这是我的。

    // Text
    $search = 'bar soap';
    $parsedSearch = explode(' ', 'bar soap');

    // Create pattern
    $patterns = [];
    $patterns[] = $search; // bar soap
    $patterns[] = $parsedSearch[1] . ' ' . $parsedSearch[0]; // soap bar
    $patterns[] = $parsedSearch[0]; //bar
    $patterns[] = $parsedSearch[1]; //soap


    // Set Query
    $query = "select `inventories`.*, MATCH (title, short_description, brand, long_description, inventory_code, product_code) AGAINST ('bar soap' IN BOOLEAN MODE) as score from `inventories` where MATCH (title, short_description, brand, long_description, inventory_code, product_code) AGAINST ('bar soap' IN BOOLEAN MODE) order by field(`score`," . implode(',', $patterns) . ")";

    return $query;

在这里,我们仅使用内置的count方法来计算大海捞针中的针数。