[英]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.