1. 程式人生 > >python字串以及他的匹配演算法

python字串以及他的匹配演算法

對於python字串的實現來說,它本身是一個線性表,根據前面我們講過的關於線性表的主體,我們可以實現一個字串物件,在這裡我們需要說明的是,python字串是一個不可變的物件,而且它的實現是一個一體式的順序表的實現(概念見前面文章)
所以,對於一個字串的物件,它除了有字元儲存空間外還有字串長度和一些配置資訊的空間。(注意一點:python沒有字元物件,單個字元也認為是一個字串物件)
所以對於字串的長度len函式和按下標取值複雜度都是O(1),但是其他的操作,如字串的複製,切片等,都是O(n)。
再講一下字串的複製(切片)的過程,這些過程都會建立一個新的字串,python首先會計算出所需要儲存空間的大小,然後一個個的計算出要儲存再空間裡的字串。這是python字串複製(切片)的一個過程。

對於字串中子串的查詢,是一個高深的問題,當前的演算法實現中經典的有兩種,一種是樸素匹配演算法,一種是無回溯的KMP演算法。

接下來我們將樸素的匹配演算法。
過程是:
目標字串t, 模式字串p。
將p中的字元依次跟t中的比較,如果有一個不匹配,將t字元移到下一位, 再講p中的字元一個個的匹配,知道返回t中與p匹配的字串。
這裡有兩種實現方法,一種返回第一個匹配的子串,另一種返回左右匹配子串的首字元的位置。實現如下:

#第一種
def naive_matching(t, p):
    # 這種找出第一個子串匹配的位置
    m, n = len(p), len(t)
    i, j = 0, 0
    while i < m and j < n:
        if p[i] == t[j]:
            i, j = i + 1, j + 1
        else:
            i, j = 0, j-i+1
    if i == m:
        return j -i
    return -1

print(naive_matching('fwekfwe', 'we'))
>>> 1

第二種

def naive_matching(t, p):
    list = []
    # 用於儲存匹配子串的首字元位置
    for i in range(len(t)):
        x, z, times = i, 0, len(p)
        if p[z] == t[i]:
            while times > 1:
                z += 1
                x += 1
                if p[z] != t[x]:
                    break
                times -= 1
            else:
            # 當while/for迴圈正常退出時才會執行相應的else語句塊
                list.append(i)
    return list
# 這種匹配可以找出所有匹配子串的位置

print(naive_matching('rewwwtrtwewrfrwe', 'ww'))
>>> [2, 3]

這兩種實現方法的複雜度相對而言都比較高(有回溯),下一篇我們會將什麼是回溯和無回溯的KMP演算法。