Je travaille sur un problème de CTCI.
Le troisième problème du chapitre 1 vous fait prendre une chaîne telle que
'Mr John Smith '
et vous demande de remplacer les espaces intermédiaires par %20
:
'Mr%20John%20Smith'
L'auteur propose cette solution en Python, en l'appelant 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
Ma question:
Je comprends qu'il s'agit de O(n) en termes de balayage à travers la chaîne réelle de gauche à droite. Mais les chaînes de Python sont-elles immuables?) J'ai une chaîne et j'ajoute une autre chaîne avec l'opérateur +
, N'alloue-t-il pas l'espace nécessaire, copie sur l'original, puis recopie sur la chaîne annexée?
Si j'ai une collection de n
chaînes de longueur 1 chacune, cela prend:
1 + 2 + 3 + 4 + 5 + ... + n = n(n+1)/2
ou O (n ^ 2) fois, oui? Ou je me trompe sur la façon dont Python gère l'ajout?
Sinon, si vous êtes prêt à m'apprendre à pêcher: comment pourrais-je le découvrir par moi-même? J'ai échoué dans mes tentatives de recherche sur Google d'une source officielle. J'ai trouvé https://wiki.python.org/moin/TimeComplexity mais cela n'a rien sur les chaînes.
Dans CPython, l'implémentation standard de Python, il existe un détail d'implémentation qui en fait généralement O (n), implémenté dans le code que la boucle d'évaluation du bytecode appelle +
ou +=
avec deux opérandes de chaîne . Si Python détecte que l'argument de gauche n'a pas d'autres références, il appelle realloc
pour tenter d'éviter une copie en redimensionnant la chaîne en place. Ce n'est pas quelque chose que vous devriez jamais compter on, car c'est un détail d'implémentation et parce que si realloc
finit par devoir déplacer fréquemment la chaîne, les performances se dégradent quand même en O (n ^ 2).
Sans le détail d'implémentation étrange, l'algorithme est O (n ^ 2) en raison de la quantité quadratique de copie impliquée. Un code comme celui-ci n'aurait de sens que dans un langage avec des chaînes mutables, comme C++, et même en C++, vous voudriez utiliser +=
.
L'auteur s'appuie sur une optimisation qui se trouve ici, mais qui n'est pas explicitement fiable. strA = strB + strC
Est généralement O(n)
, ce qui rend la fonction O(n^2)
. Cependant, il est assez facile de s'assurer que tout le processus est O(n)
, utilisez un tableau:
output = []
# ... loop thing
output.append('%20')
# ...
output.append(char)
# ...
return ''.join(output)
En bref, l'opération append
est amortieO(1)
, (bien que vous puissiez la renforcer O(1)
en pré-allouant le tableau à la bonne taille), créant la boucle O(n)
.
Et puis le join
est aussi O(n)
, mais ça va parce qu'il est en dehors de la boucle.
J'ai trouvé cet extrait de texte sur Python Speed> Utilisez les meilleurs algorithmes et outils les plus rapides :
La concaténation de chaînes est mieux effectuée avec
''.join(seq)
qui est un processusO(n)
. En revanche, l'utilisation des opérateurs'+'
Ou'+='
Peut entraîner un processusO(n^2)
car de nouvelles chaînes peuvent être créées pour chaque étape intermédiaire. L'interpréteur CPython 2.4 atténue quelque peu ce problème; cependant,''.join(seq)
reste la meilleure pratique
Pour les futurs visiteurs: Puisqu'il s'agit d'une question CTCI, aucune référence à l'apprentissage rllib package n'est requise ici, spécifiquement selon OP et le livre, cette question concerne les tableaux et les cordes.
Voici une solution plus complète, inspirée du pseudo de @ 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'))