私はCTCIの問題に取り組んでいます。
第1章の3番目の問題では、次のような文字列を使用します。
_'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不変?文字列があり、_+
_演算子を使用して別の文字列を追加します。必要なスペースを割り当て、元の文字列をコピーしてから、追加文字列をコピーしませんか?
長さ1のn
文字列のコレクションがある場合、次のようになります。
1 + 2 + 3 + 4 + 5 + ... + n = n(n+1)/2
またはO(n ^ 2)時間、はい?または、Pythonがアペンドを処理する方法を間違えていますか?
あるいは、釣りの方法を教えてくれたら、どうすれば自分でこれを見つけることができますか? Googleを公式ソースにしようとする試みは失敗しました。 https://wiki.python.org/moin/TimeComplexity が見つかりましたが、これには文字列には何もありません。
Pythonの標準実装であるCPythonには、これを通常O(n)にする実装の詳細があり、 2つの文字列オペランドを持つ+
または+=
のバイトコード評価ループが呼び出すコードに実装されます 。 Pythonは、左の引数に他の参照がないことを検出した場合、realloc
を呼び出して、文字列を適切なサイズに変更することでコピーを回避しようとします。 on、これは実装の詳細であり、realloc
が文字列を頻繁に移動する必要がある場合、パフォーマンスはいずれにしてもO(n ^ 2)に低下するためです。
奇妙な実装の詳細がないと、アルゴリズムは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
操作はamortizedO(1)
です(ただし、配列を右側に事前に割り当てることで強力にO(1)
にすることができます)サイズ)、ループO(n)
を作成します。
join
もO(n)
ですが、ループ外にあるので大丈夫です。
Pythonの速度>最適なアルゴリズムと最速のツールを使用する :でこのテキストスニペットを見つけました。
文字列の連結は、
''.join(seq)
プロセスであるO(n)
を使用するのが最適です。対照的に、_'+'
_または_'+='
_演算子を使用すると、各中間ステップで新しい文字列が作成されるため、O(n^2)
プロセスが発生する可能性があります。 CPython 2.4インタープリターはこの問題を多少軽減します。ただし、''.join(seq)
は引き続きベストプラクティスです
将来の訪問者の場合:これはCTCIの質問であるため、学習への参照 rllib パッケージは、特にここでは必要ありません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'))