Un de mes amis s'est vu poser la question suivante aujourd'hui lors d'une entrevue pour le poste de développeur de logiciels:
Étant donné deux chaînes s1
et s2
comment allez-vous vérifier s'il s1
existe une version pivotée de s2
?
Exemple:
Si s1 = "stackoverflow"
alors voici quelques-unes de ses versions tournées:
"tackoverflows"
"ackoverflowst"
"overflowstack"
où as "stackoverflwo"
n'est pas une version pivotée.
La réponse qu'il a donnée était:
Prenez
s2
et trouvez le préfixe le plus long qui est une sous-chaîne des1
, qui vous donnera le point de rotation. Une fois que vous avez trouvé ce point, arrêtez-vouss2
à ce point pour obtenirs2a
ets2b
, puis vérifiez simplement siconcatenate(s2a,s2b) == s1
Cela ressemble à une bonne solution pour moi et mon ami. Mais l'intervieweur a pensé le contraire. Il a demandé une solution plus simple. S'il vous plaît, aidez-moi en disant comment feriez-vous cela Java/C/C++
?
Merci d'avance.
Réponses:
Assurez
s1
- vous d'abord ets2
sont de la même longueur. Ensuite, vérifiez sis2
une sous-chaîne ests1
concaténée avecs1
:En Java:
la source
(s1+s1).contains(s2)
en Java.s1+s1
. De toute évidence, toutes ses sous-chaînes de tailles1.length
sont des rotations des1
, par construction. Par conséquent, toute chaîne de tailles1.length
qui est une sous-chaîne des1+s1
doit être une rotation des1
.Une meilleure réponse serait sûrement: "Eh bien, je demanderais à la communauté stackoverflow et j'aurais probablement au moins 4 très bonnes réponses en 5 minutes". Les cerveaux sont bons et tout, mais j'accorderais une valeur plus élevée à quelqu'un qui sait travailler avec les autres pour obtenir une solution.
la source
Un autre exemple de python (basé sur LA réponse):
la source
s2
plutôt qu'às1
trop ... puis j'ai réalisé que la relation était symétrique de toute façon.in
opérateur n'utilise-t-il pas un algorithme O (n)?s1 in s2
est optimisé. Voir effbot.org/zone/stringlib.htm pour la description de l'algorithme. Google semble indiquer que Java n'a pas de recherche de chaîne rapide (voir johannburkard.de/software/stringsearch par exemple) bien que je doute que cela casserait quoi que ce soit s'ils le changeaient.Comme d'autres ont soumis une solution de complexité temporelle quadratique dans le pire des cas, j'ajouterais une solution linéaire (basée sur l' algorithme KMP ):
exemple de travail
la source
EDIT: La réponse acceptée est clairement plus élégante et efficace que cela, si vous la repérez. J'ai laissé cette réponse comme ce que je ferais si je n'avais pas pensé à doubler la chaîne d'origine.
Je le ferais simplement par force brute. Vérifiez d'abord la longueur, puis essayez tous les décalages de rotation possibles. Si aucun ne fonctionne, retournez false - si l'un d'eux fonctionne, retournez true immédiatement.
Il n'y a pas besoin de concaténer en particulier - utilisez simplement des pointeurs (C) ou des index (Java) et parcourez les deux, un dans chaque chaîne - à partir du début d'une chaîne et du décalage de rotation candidat actuel dans la deuxième chaîne, et encapsuler si nécessaire . Vérifiez l'égalité des caractères à chaque point de la chaîne. Si vous arrivez à la fin de la première chaîne, vous avez terminé.
Ce serait probablement aussi facile à concaténer - bien que probablement moins efficace, au moins en Java.
la source
En voici une utilisant regex juste pour le plaisir:
Vous pouvez le rendre un peu plus simple si vous pouvez utiliser un caractère de délimiteur spécial garanti de ne pas être dans l'une ou l'autre des chaînes.
Vous pouvez également utiliser lookbehind avec une répétition finie à la place:
la source
Whoa, whoa ... pourquoi tout le monde est si ravi d'une
O(n^2)
réponse? Je suis certain que nous pouvons faire mieux ici. LA réponse ci-dessus inclut uneO(n)
opération enO(n)
boucle (l'appel substring / indexOf). Même avec un algorithme de recherche plus efficace; direBoyer-Moore
ouKMP
, le pire des cas est toujoursO(n^2)
avec des doublons.Une
O(n)
réponse aléatoire est simple; prendre un hachage (comme une empreinte digitale Rabin) qui prend en charge uneO(1)
fenêtre coulissante; chaîne de hachage 1, puis chaîne de hachage 2, puis déplacez la fenêtre de hachage 1 autour de la chaîne et voyez si les fonctions de hachage entrent en collision.Si nous imaginons que le pire des cas est quelque chose comme "scanner deux brins d'ADN", alors la probabilité de collisions augmente, et cela dégénère probablement en quelque chose comme
O(n^(1+e))
ou quelque chose (deviner juste ici).Enfin, il existe une
O(nlogn)
solution déterministe qui a une très grande constante à l'extérieur. Fondamentalement, l'idée est de prendre une convolution des deux cordes. La valeur maximale de la convolution sera la différence de rotation (si elles sont tournées); unO(n)
chèque confirme. La bonne chose est que s'il y a deux valeurs maximales égales, elles sont toutes les deux également des solutions valides. Vous pouvez faire la convolution avec deux FFT et un produit scalaire, et un iFFT, doncnlogn + nlogn + n + nlogn + n == O(nlogn)
.Étant donné que vous ne pouvez pas remplir de zéros et que vous ne pouvez pas garantir que les chaînes ont une longueur de 2 ^ n, les FFT ne seront pas les plus rapides; ce seront les lents,
O(nlogn)
mais toujours une constante beaucoup plus grande que l'algorithme CT.Tout cela dit, je suis absolument, 100% positif qu'il existe une
O(n)
solution déterministe ici, mais sacrément si je peux la trouver.la source
%stringsize
) est garanti comme étant un temps linéaire.Fist, assurez-vous que les 2 cordes ont la même longueur. Ensuite, en C, vous pouvez le faire avec une simple itération de pointeur.
la source
Voici un
O(n)
algorithme en place. Il utilise l'<
opérateur pour les éléments des chaînes. Ce n'est pas le mien bien sûr. Je l'ai pris d' ici (le site est en polonais. Je suis tombé dessus une fois dans le passé et je n'ai pas trouvé quelque chose comme ça maintenant en anglais, donc je montre ce que j'ai :)).la source
Je suppose que c'est mieux de le faire dans
Java
:En Perl je ferais:
ou encore mieux en utilisant la fonction d' index au lieu de l'expression régulière:
la source
\Q
dans/\Q$string2/
.\Q
cite tous les caractères spéciaux dans$string2
. Sans elle,.
serait considérée comme une rotation de n'importe quelle chaîne de 1 caractère.Je ne sais pas si c'est la méthode la plus efficace, mais elle pourrait être relativement intéressante : la transformation Burrows-Wheeler . Selon l'article WP, toutes les rotations de l'entrée produisent la même sortie. Pour des applications telles que la compression ce n'est pas souhaitable, donc la rotation d'origine est indiquée (par exemple par un index; voir l'article). Mais pour une comparaison simple indépendante de la rotation, cela semble idéal. Bien sûr, ce n'est pas nécessairement idéalement efficace!
la source
Prenez chaque personnage comme une amplitude et effectuez une transformation de Fourier discrète sur eux. S'ils ne diffèrent que par la rotation, les spectres de fréquence seront identiques à l'erreur d'arrondi près. Bien sûr, cela est inefficace, sauf si la longueur est une puissance de 2, vous pouvez donc faire une FFT :-)
la source
Personne n'a encore proposé une approche modulo, alors en voici une:
Production:
[EDIT: 2010-04-12]
piotr a remarqué la faille dans mon code ci-dessus. Il génère des erreurs lorsque le premier caractère de la chaîne se produit deux fois ou plus. Par exemple, le
stackoverflow
test aowstackoverflow
abouti à faux, alors que cela devrait être vrai.Merci piotr d'avoir repéré l'erreur.
Maintenant, voici le code corrigé:
Voici la sortie:
Voici l'approche lambda:
Voici la sortie de l'approche lambda:
la source
Comme personne n'a donné de solution C ++. le voici:
la source
L'astuce simple de rotation du pointeur d'Opera fonctionne, mais elle est extrêmement inefficace dans le pire des cas en temps d'exécution. Imaginez simplement une chaîne avec de nombreuses séries répétitives de caractères, c'est-à-dire:
La "boucle jusqu'à ce qu'il y ait un décalage, puis incrémenter d'un et réessayer" est une approche horrible, sur le plan du calcul.
Pour prouver que vous pouvez faire l'approche de concaténation en C simple sans trop d'effort, voici ma solution:
Ceci est linéaire dans le temps d'exécution, au détriment de l'utilisation de la mémoire O (n) en surcharge.
(Notez que l'implémentation de strstr () est spécifique à la plate-forme, mais si elle est particulièrement mortelle, elle peut toujours être remplacée par une alternative plus rapide telle que l'algorithme de Boyer-Moore)
la source
strstr()
en O (n + m)? De plus, si la norme (ou autre chose) ne vous garantit pas un temps d'exécution linéaire destrstr()
, vous ne pouvez pas affirmer que l'algorithme entier a une compexité temporelle linéaire.s1SelfConcat
: ce n'est que depuis C9x que C autorise les tailles de tableau variables (bien que GCC l'a autorisé beaucoup plus longtemps), et vous aurez des problèmes pour allouer de grandes chaînes sur la pile. Yosef Kreinin a écrit un article de blog très amusant sur ce problème. De plus, votre solution est toujours en quadratique avec Boyer-Moore; vous voulez KMP.C #:
la source
J'aime LA réponse qui vérifie si s2 est une sous-chaîne de s1 concaténée avec s1.
Je voulais ajouter une optimisation qui ne perd pas son élégance.
Au lieu de concaténer les chaînes, vous pouvez utiliser une vue de jointure (je ne sais pas pour un autre langage, mais pour C ++ Boost.Range fournir ce type de vues).
Comme la vérification si une chaîne est une sous-chaîne d'une autre a une complexité moyenne linéaire (la pire des situations est quadratique), cette optimisation devrait améliorer la vitesse d'un facteur 2 en moyenne.
la source
Une réponse Java pure (contrôles sans null)
la source
Et maintenant pour quelque chose de complètement différent.
Si vous voulez une réponse très rapide dans un contexte contraint lorsque les chaînes ne sont pas en rotation
D'accord, cela peut échouer, mais il est très rapide de dire si les chaînes ne correspondent pas et si elles correspondent, vous pouvez toujours utiliser un autre algorithme comme la concaténation de chaînes pour vérifier.
la source
Une autre solution Ruby basée sur la réponse:
la source
Il est très facile d'écrire en PHP à l'aide des fonctions
strlen
etstrpos
:Je ne sais pas ce qui
strpos
utilise en interne, mais s'il utilise KMP, ce sera linéaire dans le temps.la source
Inversez l'une des chaînes. Prenez la FFT des deux (en les traitant comme de simples séquences d'entiers). Multipliez les résultats ensemble par points. Transformez en utilisant la FFT inverse. Le résultat aura un seul pic si les cordes sont des rotations les unes des autres - la position du pic indiquera de combien elles sont tournées les unes par rapport aux autres.
la source
Pourquoi pas quelque chose comme ça?
Bien sûr, vous pouvez écrire votre propre fonction IndexOf (); Je ne sais pas si .NET utilise une méthode naïve ou une méthode plus rapide.
Naïve:
Plus rapide:
Edit: je pourrais avoir des problèmes ponctuels; n'a pas envie de vérifier. ;)
la source
Je ferais cela en Perl :
la source
la source
Inscrivez - vous
string1
avecstring2
et utiliser l' algorithme KMP pour vérifier sistring2
est présent dans la chaîne nouvellement formée. Parce que la complexité temporelle de KMP est moindre quesubstr
.la source