La plus grande sous-chaîne commune


30

Créez un programme ou une fonction qui prend une liste de chaînes en entrée et génère la chaîne la plus longue qui est une sous-chaîne de toutes les chaînes d'entrée. S'il y a plusieurs sous-chaînes de même longueur et plus de sous-chaînes, sortez l'une d'entre elles.

  • Cela peut signifier la sortie de la chaîne vide.
  • S'il existe plusieurs sorties valides, vous pouvez en sortir n'importe laquelle. Vous n'êtes pas obligé de fournir une sortie cohérente pour une entrée donnée tant que la sortie est toujours valide.
  • Il y aura toujours au moins une chaîne en entrée, mais il se peut qu'il n'y ait pas de chaîne non vide.
  • Tous les caractères ASCII imprimables peuvent apparaître dans l'entrée. Vous pouvez supposer que ce sont les seuls personnages qui apparaissent.
  • Vous pouvez prendre des entrées ou produire des sorties par l'une des méthodes par défaut .
  • Les failles standard ne sont pas autorisées.
  • Il s'agit de - moins il y a d'octets de code, mieux c'est.

Cas de test:

[Inputs] -> [Valid outputs (choose one)]

["hello", "'ello"] -> ["ello"]
["very", "much", "different"] -> [""]
["empty", "", "STRING"] -> [""]
["identical", "identical"] -> ["identical"]
["string", "stRIng"] -> ["st", "ng"]
["this one", "is a substring of this one"] -> ["this one"]
["just one"] -> ["just one"]
["", "", ""] -> [""]
["many outputs", "stuptuo ynam"] -> ["m", "a", "n", "y", " ", "o", "u", "t", "p", "s"]
["many inputs", "any inputs", "ny iii", "yanny"] -> ["ny"]
["%%not&", "ju&#st", "[&]alpha_numeric"] -> ["&"]


2
@ Adám Cette question demande la sous- séquence commune la plus longue , pas la sous-chaîne.
Poignée de porte

1
Les chaînes seront-elles uniquement alphanumériques, ou alphabétiques, ou uniquement imprimables-ascii?
Incarnation de l'ignorance

@EmbodimentofIgnorance Tous les caractères ASCII imprimables peuvent apparaître dans l'entrée.
Sara J

2
@Shaggy En général, non. Si les deux peuvent être distingués, cela undefinedsignifie qu'il n'y a pas de chaîne de sortie valide. Si la chaîne vide (ou toute autre chaîne) est une sortie valide, affirmer qu'il n'y a pas de sortie valide est incorrect.
Sara J

Réponses:


8

Python 2 , 82 octets

f=lambda h,*t:h and max(h*all(h in s for s in t),f(h[1:],*t),f(h[:-1],*t),key=len)

Essayez-le en ligne!

Prend l'entrée éclaboussée. Expirera pour les entrées où la première chaîne est longue.

L'idée est de prendre des sous-chaînes des premières chaînes hpour trouver la plus longue qui apparaît dans toutes les chaînes restantes t. Pour ce faire, nous nous branchons récursivement sur la suppression du premier ou du dernier caractère de h.


Python 2 , 94 octets

lambda l:max(set.intersection(*map(g,l)),key=len)
g=lambda s:s and{s}|g(s[1:])|g(s[:-1])or{''}

Essayez-le en ligne!

Une méthode plus directe. La fonction auxiliaire ggénère l'ensemble de toutes les sous-chaînes de s, et la fonction principale prend la plus longue de leur intersection.


8

Brachylog (v2), 3 9 octets

{sᵛ}ᶠlᵒtw

Essayez-le en ligne!

Programme complet. Entrée depuis l'entrée standard (sous forme de liste de chaînes de style JSON), sortie vers la sortie standard.

Explication

{sᵛ}ᶠlᵒtw
 s         Find a substring
  ᵛ          of every element {of the input}; the same one for each
{  }ᶠ      Convert generator to list
     lᵒt   Take list element with maximum length
        w  Output it

Apparemment, l'ordre de départage sn'est pas ce qu'il est dans presque tout le reste dans Brachylog, nous devons donc le remplacer manuellement pour produire la sortie la plus longue. (C'est un peu frustrant: quatre caractères supplémentaires pour le remplacement, plus deux caractères de regroupement car Brachylog n'analyse pas deux métaprédicates d'affilée.)

Brachylog sne renvoie pas de sous-chaînes vides, nous avons donc besoin d'un peu d'astuce pour contourner cela: au lieu de soumettre une fonction (ce qui est normalement fait), nous écrivons un programme complet, en sortie sur une sortie standard. De cette façon, s'il y a une sous-chaîne commune, nous la sortons simplement et nous avons terminé. S'il n'y a pas de sous-chaîne commune, le programme génère des erreurs - mais il n'imprime toujours rien sur la sortie standard, il génère donc la chaîne nulle comme prévu.


1
J'ai essayé ceci avec l'entrée ["many inpuabts", "any inabputs", "ny iabii", "yanabny"]. Je m'attendais aux résultats ab et ny . Mais seulement obtenu le résultat a . Est-ce que je fais quelque chose de mal ?
t-clausen.dk

1
Ugh, il me semble que je me suis souvenu de l'ordre de départage pour le smal, et le remplacement de l'ordre de départage est plutôt coûteux en octets. Faire cela maintenant de toute façon, car il est important que la réponse soit correcte. D'une manière ou d'une autre, aucun des cas de test que j'ai essayés n'a remarqué la différence.
ais523

1
@ ais523 L'ordre sproduit des sous-chaînes est en donnant d'abord tous les préfixes de l'entrée (le plus long en premier), puis en supprimant le premier et en répétant
Kroppeb

5

Gelée , 12 6 octets

Ẇ€f/ṫ0

Essayez-le en ligne!

Merci à @JonathanAllan pour avoir économisé 6 octets!


Je crois que Ẇ€œ&/Ṫḟ0ferait le travail et économiserait quatre octets puisque les sous-chaînes sont déjà ordonnées par longueur, d'où le résultat filtré sera; alors tout ce qui reste est que quand il n'y a pas de correspondance, tail produit un zéro, et comme nous sommes garantis des listes de caractères, nous pouvons simplement les filtrer.
Jonathan Allan

Je pense aussi que je œ&/pourrais être remplacé par en f/sauver un autre
Jonathan Allan

J'ai soumis une demande d'extraction pour (espérons-le) faire du résultat de la réduction d'une liste vide une liste vide (plutôt que de déclencher une TypeError). Si cela se confond, je crois que cette réponse pourrait alors devenir un six octets avec Ẇ€f/ṛ/.
Jonathan Allan

@JonathanAllan sonne bien. Merci pour les autres conseils - j'espère que vous avez été heureux que je les intègre.
Nick Kennedy

Oui, la raison de ces commentaires était de vous permettre d'incorporer les idées dans votre message.
Jonathan Allan

5

Ruby 2.6, 76 59 54 octets

->a{*w=a;w.find{|r|w<<r.chop<<r[1..];a.all?{|s|s[r]}}}

Essayez-le en ligne! - Version Ruby 2.5 (56 octets)

Comment?

Créez une liste de correspondances potentielles, initialement définie sur le tableau d'origine. Itérer sur la liste et si une chaîne ne correspond pas, ajoutez 2 nouvelles chaînes à la fin de la liste, en coupant le premier ou le dernier caractère. À la fin, une correspondance (éventuellement une chaîne vide) sera trouvée.

Merci à Kirill L pour -2 octets et à l'histocrate pour un autre -2


4

R , 119 116 108 106 octets

function(S,`?`=nchar,K=max(?S),s=Reduce(intersect,lapply(S,substring,0:K,rep(0:K,e=K+1))))s[which.max(?s)]

Essayez-le en ligne!

Trouvez toutes les sous-chaînes de chaque chaîne, trouvez l'intersection de chaque liste de sous-chaînes, puis retournez finalement (une des) la plus longue.

-3 octets grâce à Kirill L.

-8 octets utilisant lapply au lieu de Map

-2 octets merci encore à Kirill L., supprimant les accolades


Je n'ai pas le temps de vérifier, mais si je ne me trompe pas, 2 occurrences de ncharsuffisent pour sauver quelque chose en se déclarant ncharopérateur unaire.
Kirill L.

@KirillL. oui, il est plus court de 2 octets. Merci! Le crénelage listnous donne également -3 octets.
Giuseppe

Vous pouvez également déposer des accolades pour un autre -2
Kirill L.

@KirillL. Merci! Je suis un peu inquiet que je vais commencer à faire ça avec le code de production ...
Giuseppe

c'est le problème avec le golf dans une langue que vous utilisez tous les jours
MickyT

4

05AB1E , 14 9 8 octets

€Œ.«ÃéθJ

-6 octets grâce à @Adnan .

Essayez-le en ligne ou vérifiez tous les cas de test .

Explication:

€Œ       # Get the substring of each string in the (implicit) input-list
       # Right-reduce this list of list of strings by:
    Ã    #  Only keep all the strings that are present in both list of strings
     é   # Sort by length
      θ  # And pop and push its last item
         # The substrings exclude empty items, so if after the reduce an empty list remains,
         # the last item will also be an empty list,
       J # which will become an empty string after a join
         # (after which the result is output implicitly)

1
Je pense que €Œ.«Ãõªéθdevrait fonctionner pour 9 octets.
Adnan

@Adnan Attendez, nous avons une réduction .. Comment ai-je pu manquer ça. : SI a essayé Å«Ã, mais ne s'est pas rendu compte que j'aurais dû utiliser à la .«Ãplace .. Merci!
Kevin Cruijssen

1
En fait, je pense que cela €Œ.«ÃéθJdevrait fonctionner pour 8.
Adnan

4

Zsh , 126 ... 96 octets

-3 octets de l'arithmétique pour, -6 octets de l'implicite "$@"(merci roblogic), -5 octets de la suppression inutile { }, -1 octet de la forme abrégée de for, -1 octet en utilisant repeat, -1 octet en concaténant for s ($b)avec son corps, -13 octets en changeant la boucle de répétition pour certains jank d'évaluation.

for l
eval a=\( \$l\[{1..$#l},{1..$#l}\] \)&&b=(${${b-$a}:*a})
for s ($b)(($#x<$#s))&&x=$s
<<<$x

Essayez-le en ligne! Essayez-le en ligne! Essayez-le en ligne!

Nous lisons toutes les sous-chaînes possibles dans le tableau a, puis définissons bl'intersection des tableaux aet b. La construction ${b-$a}ne se substituera $aqu'à la première itération: contrairement à son expansion sœur ${b:-$a}, elle ne se substituera pas quand best définie mais vide.

for l;                              # implicit "$@"

# === OLD ===
{
    a= i=                           # empty a and i
    repeat $[$#l**2]                # compound double loop using div/mod
        a+=($l[++i/$#l+1,i%$#l+1])  # append to a all possible substrings of the given line
#               1+i/$#l             # 1,1,1...,  1,1,2,2,2,... ...,  n,n
#                       1+i%$#l     # 1,2,3...,n-1,n,1,2,3,... ...,n-1,n
#       a+=( $l[       ,     ] )    # append that substring to the array
# === NEW ===
    eval a=\( \
        \$l\[{1..$#l},{1..$#l}\] \  # The {bracket..expansions} are not escaped
    \) &&
# ===     ===
    b=( ${${b-$a}:*a} )
#         ${b-$a}                   # if b is unset substitute $a
#       ${       :*a}               # take common elements of ${b-$a} and $a
#   b=(               )             # set b to those elements
}
for s ($b)                          # for every common substring
    (( $#x < $#s )) && x=$s         # if the current word is longer, use it
<<<$x                               # print to stdout

Comment ça marche? a+=( $l[1+i/$#l,1+i%$#l] )
roblogic

1
@roblogic Je pense que je l'ai mieux expliqué maintenant, vérifiez l'édition. L'idée est de boucler vers n ^ 2 et d'utiliser / et% au lieu d'utiliser 2 forboucles imbriquées
GammaFunction

1
vous pourriez être capable de couper for l in "$@"simplement for l;- c'est un truc bash
roblogic

je dois dire que zsh est tellement plus élégant que bash. Il n'y a rien d'analogue à cette belle comparaison de tableaux AFAIKb=(${${b-$a}:*a})}
roblogic

1
Il y a des choses intéressantes que vous pouvez faire avec, et ce n'est pas si populaire. Cela se traduit par l'ajout d'une réponse zsh à la plupart des questions que je rencontre. : P Si vous voulez apprendre zsh, je recommande man zshexpnet man zshparamsurtout. Je les ai toujours ouverts lorsque j'écris une réponse.
GammaFunction

3

Haskell , 80 octets

import Data.List
f(x:r)=last$sortOn(0<$)[s|s<-inits=<<tails x,all(isInfixOf s)r]

Essayez-le en ligne!

Obtenez tous les suffixes ( tails) du premier mot xde la liste et prenez tous les préfixes ( inits) de ces suffixes pour obtenir toutes les sous s- chaînes de x. Gardez chacune de sces isInfixOf allchaînes dans la liste restante r. Triez ces sous-chaînes par longueur (en utilisant l' (0<$)astuce ) et renvoyez la dernière.


3

Retina 0.8.2 , 48 octets

M&!`(?<=^.*)(.+)(?=(.*\n.*\1)*.*$)
O#$^`
$.&
1G`

Essayez-le en ligne! Explication:

M&!`(?<=^.*)(.+)(?=(.*\n.*\1)*.*$)

Pour chaque suffixe de la première chaîne, recherchez le préfixe le plus long qui est également une sous-chaîne de toutes les autres chaînes. Énumérez tous ces préfixes de suffixe (c.-à-d. Sous-chaînes). S'il n'y a pas de sous-chaînes correspondantes, nous nous retrouvons avec la chaîne vide, ce que nous voulons de toute façon.

O#$^`
$.&

Triez les sous-chaînes dans l'ordre inverse de la longueur.

1G`

Ne conservez que la première, c'est-à-dire la sous-chaîne la plus longue.


Soit le nnombre de chaînes d'arguments. Alors ça (?=(.*\n.*\1)*.*$)devrait l'être (?=(.*\n.*\1){n-1}.*$), non? Cas de test:["very", "different", "much"] -> [""]
Mazzy

1
@mazzy Je ne vois pas le problème: essayez-le en ligne!
Neil

Ce n'est pas un problème. avec {n}vous pouvez supprimer les modèles de début et de fin et les conserver (.+)(?=(.*\n.*\1){n}si Retina permet d'écrire nplus court que(?<=^.*).*$
mazzy

@mazzy Je ne peux pas dans Retina 0.8.2, et dans Retina 1, je devrais jouer avec eval, qui serait probablement plus long de toute façon.
Neil

3

Requête TSQL, 154 octets

USE master
DECLARE @ table(a varchar(999)collate Latin1_General_CS_AI,i int identity)
INSERT @ values('string'),('stRIng');

SELECT top 1x FROM(SELECT
distinct substring(a,f.number,g.number)x,i
FROM spt_values f,spt_values g,@ WHERE'L'=g.type)D
GROUP BY x ORDER BY-sum(i),-len(x)

Essayez-le en ligne

Rendu sensible à la casse en déclarant la colonne «a» avec un classement contenant CS (sensible à la casse).

Divisant toutes les chaînes de 2540 positions de départ (beaucoup identiques) mais les valeurs utiles varient entre 1 et 2070 et se terminant de 0 à 22 caractères après la position de départ, la position de fin pourrait être plus longue en changeant le type en `` P '' au lieu de `` L '', mais paralyserait les performances.

Ces chaînes distinctes au sein de chaque numéro de compte sont comptées. Le nombre le plus élevé sera toujours égal au nombre de lignes dans la variable de table '@'. Inverser l'ordre sur le même nombre laissera la sous-chaîne avec la plupart des correspondances en haut des résultats, suivie par la longueur inversée de la sous-chaîne, la correspondance la plus longue avec la plupart des correspondances en haut. La requête ne sélectionne que la première ligne.

Pour obtenir toutes les réponses, changez la première partie de la requête en

SELECT top 1 avec liens x FROM


3

C # (Visual C # Interactive Compiler), 320 257 octets

l=>(string.Join(",",l.Select(s=>new int[s.Length*s.Length*2].Select((i,j)=>string.Concat(s.Skip(j/-~s.Length).Take(j%-~s.Length))))
.Aggregate((a,b)=>a.Intersect(b)).GroupBy(x=>x.Length).OrderBy(x =>x.Key).LastOrDefault()?.Select(y=>y)??new List<string>()));

Essayez-le en ligne!

Accessoires pour @Expired Data et @dana


Vous pouvez simplement renvoyer la chaîne d'une fonction. Ainsi, dans le compilateur interactif, cela pourrait ressembler à ceci: 294 octets
Données expirées

1
Voici la solution sur quelques octets 215 octets
Données expirées

@ExpiredData ah parfait c'est l'exemple dont j'avais besoin :)
Innat3



3

Perl 6 , 62 60 octets

{~sort(-*.comb,keys [∩] .map(*.comb[^*X.. ^*]>>.join))[0]}

Essayez-le en ligne!

Je suis un peu ennuyé que Perl 6 ne puisse pas effectuer d'opérations de définition sur des listes de listes, c'est pourquoi il y a un supplément .combet >>là-dedans.

Une autre chose ennuyeuse est que je maxne peux pas prendre de fonction pour comparer les articles, ce qui signifie que je dois utiliser à la sortplace. Comme indiqué dans les commentaires, max peut prendre un argument, mais cela finit plus longtemps car je dois prendre en compte le maxretour de l'infini négatif lorsqu'il y a des sous-chaînes courantes ( essayez-le en ligne! ).


3
maxpeut prendre une telle fonction (arité 1 cependant), soit par position lorsqu'elle est appelée en mode OO, soit par un :byargument nommé en mode procédural.
Ven

2

Japt v2.0a0 -hF, 8 octets

Îã f@eøX

Merci à Shaggy d'avoir économisé 3 octets

Essayez-le

Îã              //Generate all substrings of the first string
 f@             //Filter; keep the substrings that satisfy the following predicate:
   e            //    If all strings of the input...
    øX          //    Contain this substring, then keep it
-h              //Take last element
-F              //If last element is undefined, default to empty string

Vous ne devriez pas avoir besoin de trier par longueur à la fin, économisant 3 octets. En outre, par -Fdéfaut , la chaîne vide.
Shaggy

2

Japt -h , 8 octets

(Je pourrais supprimer les 3 derniers octets et utiliser le -Fhdrapeau à la place, mais je ne suis pas fan de l'utilisation -F)

mã rf iP

Essayez-le ou exécutez tous les cas de test

mã rf iP     :Implicit input of array
m            :Map
 ã           :  Substrings
   r         :Reduce by
    f        :  Filter, keeping only elements that appear in both arrays
      i      :Prepend
       P     :  An empty string
             :Implicit output of last element


1

Python 2 , 103 octets

lambda b:max(reduce(set.__and__,[{d[f:e]for e in range(len(d)+2)for f in range(e)}for d in b]),key=len)

Essayez-le en ligne!

Il s'agit d'un lambda anonyme qui transforme chaque élément en l'ensemble de toutes les sous-chaînes, puis le reduces par set intersection ( set.__and__) et renvoie ensuite l' maxélément par length.


1 octet plus court avec set.intersection.
OVS


1

Perl 5 (-aln0777F/\n/ -M5.01 -MList::util=max ), 99 octets

peut être joué au golf plus certainement

map/(.+)(?!.*\1)(?{$h{$&}++})(?!)/,@F;say for grep{y///c==max map y///c,@b}@b=grep@F==$h{$_},keys%h

TIO



1

Fusain , 30 octets

≔⊟θη≔⁰ζFLη«≔✂ηζ⊕ι¹ε¿⬤θ№κεPε≦⊕ζ

Essayez-le en ligne! Le lien est vers la version détaillée du code. Cet algorithme est plus efficace et plus court que la génération de toutes les sous-chaînes. Explication:

≔⊟θη

Insérez la dernière chaîne de la liste d'entrée dans une variable.

≔⁰ζ

Mettez à zéro l'index de démarrage de la sous-chaîne.

FLη«

Boucle sur tous les indices d'extrémité de sous-chaîne possibles. (En fait, cela passe de 0 à l'exclusion de la longueur, donc la valeur est ajustée plus tard.)

≔✂ηζ⊕ι¹ε

Obtenez la sous-chaîne actuelle.

¿⬤θ№κε

Vérifiez si cette sous-chaîne est contenue dans toutes les autres chaînes d'entrée.

Pε

Si elle est surimprimée, toute sous-chaîne précédemment sortie.

≦⊕ζ

Sinon, essayez d'incrémenter l'index de démarrage de la sous-chaîne.


1

Bash , 295 .. 175 octets

Pas joli mais au moins ça marche. Essayez-le en ligne

-37 par nettoyage général ; -52 en plagiant à partir de la réponse zsh ; -26 en remplaçant le tableau par une boucle ; -2 grâce à GammaFunction ; -3 retiré i=0de la forboucle

for l;{ d=${#l}
for((;i<d**2;i++)){ a="${l:i/d:1+i%d}" k=
for n;{ [[ $n =~ $a ]]&&((k++));}
((k-$#))||b+=("$a");};}
for e in "${b[@]}";do((${#e}>${#f}))&&f="$e";done
echo "$f"

Voici le script original non golfé avec des commentaires


1
Économisez 2 de plus: vous pouvez remplacer ((k==$#))&&par ((k-$#))||. Cela vous permet également d'utiliser k=au lieu de le mettre à 0.
GammaFunction

1
Je pense que "pas joli mais au moins ça marche" est le MO pour les scripts bash :)
joeytwiddle

0

Rouge , 266 174 octets

func[b][l: length? s: b/1 n: 1 until[i: 1 loop n[t: copy/part at s i l r: on foreach u
next b[r: r and(none <> find/case u t)]if r[return t]i: i + 1]n: n + 1 1 > l: l - 1]""]

Essayez-le en ligne!

Modification de la récursivité en itération et suppression du tri.



0

JavaScript (Node.js) , 106 octets

a=>(F=(l,n,w=a[0].substr(n,l))=>l?n<0?F(--l,L-l):a.some(y=>y.indexOf(w)<0)?F(l,n-1):w:"")(L=a[0].length,0)

Essayez-le en ligne!

a=>(                      // Main function
 F=(                      //  Helper function to run through all substrings in a[0]
  l,                      //   Length
  n,                      //   Start position
  w=a[0].substr(n,l)      //   The substring
 )=>
 l?                       //   If l > 0:
  n<0?                    //    If n < 0:
   F(--l,L-l)             //     Check another length
  :a.some(                //    If n >= 0: 
   y=>y.indexOf(w)<0      //     Check whether there is any string not containing the substring
                          //     (indexOf used because of presence of regex special characters)
  )?                      //     If so:
   F(l,n-1)               //      Check another substring
  :w                      //     If not, return this substring and terminate
                          //     (This function checks from the longest substring possible, so
                          //      it is safe to return right here)
 :""                      //   If l <= 0: Return empty string (no common substring)
)(
 L=a[0].length,           //  Starts from length = the whole length of a[0]
 0                        //  And start position = 0
)

0

Gaia , 15 octets

eḋ¦&⊢⟨:l¦:⌉=¦⟩∇

Essayez-le en ligne!

e		| eval as code
 ḋ¦		| find all non-empty substrings
   &⊢		| Reduce by set intersection
              ∇	| and return the first element where
      ⟨:l¦:⌉=¦⟩	| the length is equal to the max length

0

PowerShell , 165 163 87 octets

-76 octets grâce à Nail pour l' excellente expression régulière .

"$($args-join'
'|sls "(?<=^.*)(.+)(?=(.*\n.*\1)*.*$)"-a -ca|% m*|sort Le*|select -l 1)"

Essayez-le en ligne!

Moins golfé:

$multilineArgs = $args-join"`n"
$matches = $multilineArgs|sls "(?<=^.*)(.+)(?=(.*\n.*\1)*.*$)" -AllMatches -CaseSensitive|% matches
$longestOrNull = $matches|sort Length|select -Last 1
"$longestOrNull"




0

Pyth , 16 octets

eolN.U@bZm{s./dQ

Essayez-le en ligne!

       m     Q    # Map Q (parsed input) over the following function (lambda d:
          ./d     # Partitions of d (all substrings)
         s        # Reduce on + (make one list)
        {         # deduplicate
    .U            # reduce the result on the following lambda, with starting value result[0]
      @bZ         # lambda b,Z: Intersection between b and Z
                  # Result so far: all common substrings in random order
 o                # sort the resulting sets by the following lambda function:
  lN              # lambda N: len(N)
e                 # last element of that list
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.