web-dev-qa-db-ja.com

文字列に部分文字列がある場合のPythonのランタイム

次の_if statement_のビッグOは何ですか?

_if "pl" in "Apple":
   ...
_

pythonが文字列「pl」が文字列「Apple」にあるかどうかを判断する方法の全体的な大きなOは何ですか

または文字列検索の他の部分文字列。

これは、部分文字列が文字列内にあるかどうかをテストする最も効率的な方法ですか? .find()と同じアルゴリズムを使用していますか?

18
Liondancer

python 3.4.2では、同じ関数を使用しているように見えますが、それでもタイミングが異なる場合があります。たとえば、s.find最初に、文字列などのfindメソッドを検索する必要があります。

使用されるアルゴリズムは、Boyer-MoreとHorspoolの混合です。

8
skyking

時間の複雑さはO(N)平均で、O(NM)最悪の場合(Nは長い文字列の長さ、Mは短い文字列)検索します)。

str.index()str.find()str.__contains__()in演算子)とstr.replace()にも同じアルゴリズムが使用されます。 Boyer–Moore–Horspool および Sunday アルゴリズムからのアイデアを取り入れた Boyer-Moore の簡略化です。

originalstringlibディスカッションポスト 、および fastsearch.hソースコード ;基本アルゴリズムは (Python 2.5 の紹介)以降変更されていません( 一部の低レベルの最適化とコーナーケースの修正 を除きます)。

投稿には、アルゴリズムのPythonコードの概要が含まれています。

def find(s, p):
    # find first occurrence of p in s
    n = len(s)
    m = len(p)
    skip = delta1(p)[p[m-1]]
    i = 0
    while i <= n-m:
        if s[i+m-1] == p[m-1]: # (boyer-moore)
            # potential match
            if s[i:i+m-1] == p[:m-1]:
                return i
            if s[i+m] not in p:
                i = i + m + 1 # (sunday)
            else:
                i = i + skip # (horspool)
        else:
            # skip
            if s[i+m] not in p:
                i = i + m + 1 # (sunday)
            else:
                i = i + 1
    return -1 # not found

速度の比較と同様に。

32
Martijn Pieters

timeit を使用して、自分でテストできます。

maroun@DQHCPY1:~$ python -m timeit 's = "Apple";s.find("pl")'
10000000 loops, best of 3: 0.125 usec per loop
maroun@DQHCPY1:~$ python -m timeit 's = "Apple";"pl" in s'
10000000 loops, best of 3: 0.0371 usec per loop

inの使用は確かに高速です(0.125 usecと比較して0.0371 usec)。

実際の実装では、 コード自体 を確認できます。

4
Maroun

調べるための最良の方法は、ソースを調べることだと思います。 これ は___contains___を実装するように見えます:

_static int
bytes_contains(PyObject *self, PyObject *arg)
{
    Py_ssize_t ival = PyNumber_AsSsize_t(arg, PyExc_ValueError);
    if (ival == -1 && PyErr_Occurred()) {
        Py_buffer varg;
        Py_ssize_t pos;
        PyErr_Clear();
        if (PyObject_GetBuffer(arg, &varg, PyBUF_SIMPLE) != 0)
            return -1;
        pos = stringlib_find(PyBytes_AS_STRING(self), Py_SIZE(self),
                             varg.buf, varg.len, 0);
        PyBuffer_Release(&varg);
        return pos >= 0;
    }
    if (ival < 0 || ival >= 256) {
        PyErr_SetString(PyExc_ValueError, "byte must be in range(0, 256)");
        return -1;
    }

    return memchr(PyBytes_AS_STRING(self), (int) ival, Py_SIZE(self)) != NULL;
}
_

stringlib_find() の観点から、これは fastsearch() を使用します。

3
Vlad