簡體   English   中英

迭代字符串追加的時間復雜度實際上是 O(n^2) 還是 O(n)?

[英]Is the time-complexity of iterative string append actually O(n^2), or O(n)?

我正在處理 CTCI 之外的一個問題。

第 1 章的第三個問題讓你取一個字符串,例如

'Mr John Smith '

並要求您用%20替換中間空格:

'Mr%20John%20Smith'

作者在 Python 中提供了這個解決方案,稱之為 O(n):

def urlify(string, length):
    '''function replaces single spaces with %20 and removes trailing spaces'''
    counter = 0
    output = ''
    for char in string:
        counter += 1
        if counter > length:
            return output
        elif char == ' ':
            output = output + '%20'
        elif char != ' ':
            output = output + char
    return output

我的問題:

我知道這是從左到右掃描實際字符串的 O(n)。 但是 Python 中的字符串不是不可變的嗎? 如果我有一個字符串並使用+運算符向其中添加另一個字符串,它是否會分配必要的空間,復制原始字符串,然后復制附加字符串?

如果我有n長度為 1 的字符串的集合,則需要:

1 + 2 + 3 + 4 + 5 + ... + n = n(n+1)/2

O(n^2) 時間,是嗎? 還是我在 Python 處理追加的方式上弄錯了?

或者,如果您願意教我如何釣魚:我將如何為自己找到這個? 我嘗試 Google 官方來源的嘗試沒有成功。 我找到了https://wiki.python.org/moin/TimeComplexity但這在字符串上沒有任何內容。

在 CPython(Python 的標准實現)中,有一個實現細節通常是 O(n),在字節碼評估循環調用++=的代碼中實現,帶有兩個字符串操作數 如果 Python 檢測到左參數沒有其他引用,它會調用realloc以嘗試通過調整字符串大小來避免復制。 這不是您應該依賴的東西,因為它是一個實現細節,並且因為如果realloc最終需要頻繁移動字符串,則性能無論如何都會降低到 O(n^2)。

如果沒有奇怪的實現細節,由於涉及二次復制,算法是 O(n^2)。 像這樣的代碼只在具有可變字符串的語言中才有意義,比如 C++,甚至在 C++ 中你也想使用+=

作者依賴於碰巧在這里的優化,但不是明確可靠的。 strA = strB + strC通常是O(n) ,使函數O(n^2) 但是,很容易確保整個過程是O(n) ,使用數組:

output = []
    # ... loop thing
    output.append('%20')
    # ...
    output.append(char)
# ...
return ''.join(output)

簡而言之, append操作分攤O(1) ,(盡管您可以通過將數組預先分配到正確的大小來使其強O(1) ),從而使循環O(n)

然后join也是O(n) ,但這沒關系,因為它在循環之外。

我在Python 速度 > 使用最好的算法和最快的工具上找到了這段文字:

字符串連接最好用''.join(seq) ,這是一個O(n)過程。 相比之下,使用'+''+='運算符可能會導致O(n^2)過程,因為可能會為每個中間步驟構建新字符串。 CPython 2.4 解釋器在一定程度上緩解了這個問題; 然而, ''.join(seq)仍然是最佳實踐

對於未來的訪問者:由於這是一個 CTCI 問題,因此這里不需要任何關於學習urllib包的參考,特別是根據 OP 和這本書,這個問題是關於數組和字符串的。

這是一個更完整的解決方案,靈感來自@njzk2 的偽:

text = 'Mr John Smith'#13 
special_str = '%20'
def URLify(text, text_len, special_str):
    url = [] 
    for i in range(text_len): # O(n)
        if text[i] == ' ': # n-s
            url.append(special_str) # append() is O(1)
        else:
            url.append(text[i]) # O(1)

    print(url)
    return ''.join(url) #O(n)


print(URLify(text, 13, '%20'))

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM