Stringhe accoppiabili


28

Una stringa è accoppiabile se può essere suddivisa in sottotitoli, ognuno dei quali è una stringa ripetuta due volte consecutivamente. Ad esempio, aabaaababbbabaè accoppiabile come:

aaba aaba
b b
ba ba

Data una stringa non vuota di a"se b", genera un valore Verità se è accoppiabile e un valore Falsey se non lo è.

irreparabili:

aa
abaaba
bbababbb
aabaaababbbaba
babababa
bbbbbbbbbbbb
aaababbabbabbbababbaabaabaababaaba
aaaabaab

Non abbinabile:

a
ba
baab
abaabaaba
bbbbbbbbbbbbbbb
baababbabaaaab
aaaaabbaaaaa

Ti incoraggio a trovare soluzioni non basate su regex anche quando c'è già una risposta regex più breve nella tua lingua. Puoi contrassegnarli come "nessuna regex". Per regex, intendo un sottosistema di corrispondenza del modello di stringa incorporato.


Classifica:


Possiamo usare altro che ab?
Erik the Outgolfer,

Se bbababbb è accoppiabile, perché baab e aaaaabbaaaaa no?
anche il

@rnso Da quanto ho capito, bbababbb può essere suddiviso in 3 coppie: bb, abab e bb che si concatenano in quell'ordine per formare la stringa originale, mentre gli altri due non possono.
Sunny Pun

Dalla domanda "ognuna delle quali (sottostringa) è una stringa ripetuta due volte CONSECUTIVAMENTE" e ciò non è soddisfatto con bbababbb. Altrimenti, baab può anche essere diviso in baab e aaaaabbaaaaa in aaaaa bb aaaaa.
anche il

@rnso Non so cosa intendi lì. Consecutivamente, intendo che le due ripetizioni sono una accanto all'altra. In "baa b", le due b sono separate da una, quindi non funziona.
xnor

Risposte:


11

Python 2, 68 63 byte

f=lambda s,n=1:s==2*s[:n]or''<s[n:]>-f(s,n+1)<f(s[n:])*f(s[:n])

Restituisce Vero o Falso . Provalo su Ideone .


4
Questa è una ricorsione davvero pulita, usando l'indice sia per il centro del doppio che per il centro per partizionare. È divertente che la veridicità sia considerata meno di qualcosa. Vedo alcuni miglioramenti ...
xnor

8

Retina , 11 byte

^((.+)\2)+$

Prova tutti i casi di test. I primi due byte lo rendono multilinea.

Interpretazione piuttosto letterale delle regole, ovviamente usa regex, come faranno tutti i programmi Retina.


2
Dangit, stavo aspettando da 3 settimane per pubblicare questo ...
ETHproductions

2
Anche Martin stava aspettando .
xnor

5
Ops! L'ho battuto anche solo per 10 secondi ... Beh, sono sicuro che se scrivo una risposta Hexagony mi perdonerà!
FryAmTheEggman,

5
@FryAmTheEggman Non vedo l'ora. :)
Martin Ender,

2
È esattamente lo stesso con Perl:perl -pE '$_=/^((.+)\2)+$/'
Dada,

8

Gelatina , 10 byte

ẆŒPẋ€€2F€ċ

Non esattamente efficiente ... Provalo online!

Come funziona

ẆŒPẋ€€2F€ċ  Main link. Argument: s (string)

Ẇ           Window, generate the array of all substrings of s.
 ŒP         Powerset; generate all subarrays of substrings of s.
   ẋ€€2     Repeat each substring in each subarray twice.
            For example, ["ab", "a", "b"] becomes ["abab", "aa", "bb"].
       F€   Flatten the subarrays by concatenating their strings.
         ċ  Count how many times s appears in the generated strings.

Questo ... sembra inefficiente. Per quanto tempo gli input possono essere gestiti in un lasso di tempo ragionevole?
John Dvorak,

1
È estremamente inefficiente ( O (2 ^ n ^ 2) , penso). Dovrei controllare localmente. TIO esaurisce la memoria per stringhe di lunghezza 6 .
Dennis,

8
Una stringa di lunghezza 6 impiega 3:20 minuti sulla mia macchina e richiede 6 GB di memoria.
Dennis,

1
@Dennis Non facciamo quindi un input di lunghezza 100 , perché tutto andrà in crash. Sì, anche TIO.
Erik the Outgolfer,

@EriktheGolfer Questa è una buona idea poiché rallenterà inutilmente TIO per altri usi, ma non lo bloccherà. Non appena il sistema esaurisce la memoria, il processo viene semplicemente interrotto da OOM.
Dennis,

5

Haskell, 72 69 byte (senza regex)

g(a:b:c)|a==b=g c
g x=x==[]
any(g.words.concat).mapM(\c->[[c],c:" "])

Un approccio a forza bruta. Provalo su Ideone .

Grazie a BlackCap per -3 byte.

Spiegazione

La funzione helper gprende un elenco di stringhe e verifica che sia composta da coppie di stringhe identiche, come ["aa","aa","bba","bba","ab","ab"]. La funzione principale (anonima) suddivide una stringa in tutti i modi possibili e verifica che almeno una divisione comporti un elenco che gaccetta.

g(a:b:c)                                  g on list with elements a, b and tail c,
        |a==b                              in the case that a==b,
             =g c                          recurses to the tail c.
g x=                                      g on any other list x
    x==[]                                  checks that x is empty.
                                           This includes the case where a is not equal
                                           to b, resulting in False.
any(g.words.concat).mapM(\c->[[c],c:" "]) The main function:
                    mapM(\c->[[c],c:" "])  Replace each letter c with either "c" or "c "
                                           in all possible ways, return list of results.
any(              ).                       Check that at least one result satisfies this:
            concat                          Concatenate the 1- or 2-letter strings,
      words.                                split again at each space,
    g.                                      apply g.

È possibile sostituire or.mapconany
BlackCap il

@BlackCap Certo, grazie! Inizialmente avevo any g.map(words.concat)pensato "Hey, posso giocare anya golf or" ...
Zgarb,

5

Python 2, 60 byte

f=lambda s,t='':''<s>f(s[1:],t+s[0])|f(t and s)*f(t)>-(s==t)

Spero sia corretto Funziona abbastanza lentamente e andnon sembra ottimale.


1
Ho provato a utilizzare le stringhe, ma non sono riuscito ad avvicinarmi al punteggio basato sull'indice. È intelligente and.
Dennis,

Congratulazioni! Ricorrere alla partizione era il trucco che avevo in mente.
xnor

4

Gelatina , 12 byte

ŒṖµœs€2ZEµ€S

Due byte in più rispetto alla mia altra risposta , ma questo approccio è molto più efficiente e gestisce tutti i casi di test tranne uno.

Provalo online!

Come funziona

ŒṖµœs€2ZEµ€S  Main link. Argument: s (string)

ŒṖ            Generate all partitions of s.
  µ      µ€   Map the monadic chain between the µ's over the partitions.
   œs€2         Split each string in the partition into two chunks of equal length.
       Z        Zip/transpose, collecting the first halves in one array and the
                second halves in another.
        E       Test the arrays of halves for equality.
           S  Return the sum of the results, counting the number of different
              ways s can be paired.

3

Pyth - No Regex - 13 12 byte

Verifica se una delle partizioni è composta da tutte le stringhe uguali tra loro quando tagliate in due.

sm.AqMcL2d./

Test Suite .


3

Brachylog , 14 byte (senza regex)

lye~l:1j@2zcc?

Provalo online!

Questo è troppo lento per alcuni dei casi di test

Spiegazione

ly                  The list [0, …, length(Input)]
  e~l               A list whose length is an element of the previous list
     :1j            Append itself to this list
        @2zc        Split in half, zip and concatenate so that the list contains pairs of
                      consecutive identical elements
            c?      The concatenation of that list must result in the Input

3

JavaScript (ES6), nessuna regexp, 75 74 byte

f=s=>!s|[...s].some((_,i)=>i&&s[e='slice'](0,i)==s[e](i,i+=i)&&f(s[e](i)))

Restituisce 1altrimenti accoppiabile 0. Modifica: salvato 1 byte grazie a @ edc65.


Bello! Stesso conteggio usando substrsenza modificare i. Ma con sliceripetute 3 volte è possibile salvare 1 byte aliasing
edc65

@ edc65 Come si ottiene lo stesso conteggio senza modificare i? Mi rendo conto che s.substr(i,i+i)restituisce lo stesso s.slice(i,i+=i)ma poi uso il valore modificato in iseguito ...
Neil,

è s.substr(i,i)2 byte in meno, quindi s.slice(i+i)2 byte in più
edc65

@ edc65 Oh, certo che lo è, devo aver bisogno di più caffè ...
Neil,

3

Python, 58 byte

f=lambda s,p='':s>''and(f(p)>-(s==p)<f(s))|f(s[1:],p+s[0])

Questo si basa sul metodo ricorsivo di Dennis . Anche il trucco della negazione booleana viene preso da lì.

La nuova idea è quella di ricorrere alle partizioni (p,s)della stringa originale iniziando con ('',s)e spostando ripetutamente il primo carattere di sessere l'ultimo di p. Ciò consente di fare riferimento direttamente alle parti senza affettare le stringhe. Ma, poiché la partizione inizia con pvuoto, dobbiamo stare attenti a evitare infiniti cicli di f(s)chiamata f(s).


2

JavaScript (ES6), 24 byte

x=>/^((.+)\2)+$/.test(x)

Probabilmente non si riduce di così.


Non dovrebbe essere \2?
Neil,

@Neil Per qualche motivo, ho pensato che funzionasse \1, ma aabritorna true... grazie per la correzione.
ETHproductions


2

Python, 66 64 byte

Grazie @Zgarb per -1 byte!

f=lambda x,s=1:x>x[:s]and(x==2*x[:s])|f(x[:s])&f(x[s:])|f(x,s+1)

Restituisce Trueo False.

Provalo online!

Qualsiasi aiuto per giocare a golf sarebbe apprezzato.


1

Racchetta 230 byte

(let((sl string-length)(ss substring))(if(odd?(sl s))(printf ".~n")(begin(let p((s s))(if(equal? s "")(printf "!")
(for((i(range 1(add1(/(sl s)2)))))(when(equal?(ss s 0 i)(ss s i(* 2 i)))(p(ss s(* 2 i)(sl s)))))))(printf ".~n"))))

Stampa un '!' per ogni modo in cui la stringa è accoppiabile. Stampa un '.' alla fine.

Ungolfed:

(define (f s)
  (let ((sl string-length)                              ; create short names of built-in fns
        (ss substring))
    (if (odd? (sl s))  (printf ".~n")                   ; odd length strings cannot be pairable; end here.
        (begin
          (let loop ((s s))                             ; start testing here
            (if (equal? s "") (printf "!")              ; if no remaining string, it must be pairable
                (for ((i (range 1 (add1 (/(sl s)2)))))  ; ch lengths varying from 1 to half of string length
                  (when (equal? (ss s 0 i)              ; ch if substrings are same
                                (ss s i (* 2 i)))
                    (loop (ss s (* 2 i) (sl s) ))))))   ; if yes, loop to check remaining string.
          (printf ".~n")))))                            ; End of testing.

test:

(println "Following should be pairable")
(f "bbaabbaa")            ; should produce 2 '!' since 2 ways are possible.
(f "aa")
(f "abaaba")
(f "bbababbb")
(f "aabaaababbbaba")
(f "babababa")                    ; should be pairable in 2 ways.
(f "bbbbbbbbbbbb")                ; should be pairable in many ways.
(f "aaababbabbabbbababbaabaabaababaaba")
(f "aaaabaab")
(println "Following should be unpairable")
; (f "a")
(f "ba")
(f "baab")
(f "abaabaaba")
(f "bbbbbbbbbbbbbbb")
(f "baababbabaaaab")
(f "aaaaabbaaaaa")

Produzione:

"Following should be pairable"
!!.
!.
!.
!.
!.
!!.
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!.
!.
!.
"Following should be unpairable"
.
.
.
.
.
.

1

Perl, 16 +2 = 18 byte (con regex)

Corri con le -nlbandiere. -Eè libero.

say/^((.+)\2)+$/

Correre come:

perl -nlE 'say/^((.+)\2)+$/'

Restituisce un elenco dei gruppi di acquisizione (una verità) se accoppiabile, stringa nulla se non accoppiabile.

Spiegazione

I -nlflag eseguiranno il codice in un ciclo ( -n), inserendo ogni volta l'input (con la nuova riga finale rimossa a causa di -l) nella variabile $_, quindi valutando il codice ogni volta che si immette l'input, fino a quando il programma non viene terminato manualmente. Il -Eflag consente di valutare il codice sulla riga di comando e abilita il saycomando.

say/^((.+)\2)+$/

   /^((.+)\2)+$/  #The regex engine
      (.+)\2      #Find any set of at least one character, followed by itself
     (      )+    #Do this at least one time
   /^         $/  #Make sure that this matches the entire string from start to end
say               #Output the result of the regex

Se viene trovata una corrispondenza (ad es. Se la stringa è accoppiabile), il regex restituisce un elenco dei gruppi di acquisizione, che restituisce un valore di verità, che viene quindi passato saye trasmesso . Se non viene trovata alcuna corrispondenza, il regex restituisce la stringa vuota, che valuta falsa, che viene quindi passata asay e .

Campione:

$ perl -nlE 'say/^((.+)\2)+$/'
aaababbabbabbbababbaabaabaababaaba
baababaababaaba                      #Truthy
baababbabaaaab
                                     #Falsy
bbababbb
bbb                                  #Truthy
aabaaababbbaba
bababa                               #Truthy
abaabaaba
                                     #Falsy

1

GNU Prolog, 49 46 byte

Probabilmente funziona anche in altre varianti, sebbene non rappresentino tutte le stringhe allo stesso modo; La rappresentazione di GNU Prolog è utile per questo problema.

Non è chiaro se questo conta come usare regex o no. Non utilizza alcuna funzionalità simile a regex, ma l'intera semantica del linguaggio è simile a quella di regex.

Nuova versione (usa il trucco di ricorsione visto in alcune altre risposte):

s(X):-append(A,B,X),(A=B;A\=X,B\=X,s(A),s(B)).

Versione precedente:

s(X):-X=[];append(A,B,X),B\=X,append(C,C,A),s(B).

Questo è un predicato (l'equivalente di una funzione di Prolog) chiamato s, non un programma completo. Usalo in questo modo:

| ?- s("aa").
true ?
yes
| ?- s("aaababbabbabbbababbaabaabaababaaba").
true ?
yes
| ?- s("baababbabaaaab").
no
| ?- s("bbbbbbbbbbbbbbb").
no

Una caratteristica interessante della soluzione precedente è che se chiedi all'interprete "ci sono più soluzioni?" tramite l'uso di ;al true ?prompt (anziché chiedere "c'è qualche soluzione" premendo Invio al prompt, come ho fatto sopra), restituisce "vero" un numero di volte uguale al numero di modi diversi in cui la stringa può essere espressa nella forma data (ad es. restituisce "true" due volte con s("aaaa")., poiché può essere analizzato come (a a)(a a)o come (aa aa)).

I programmi Prolog sono spesso reversibili (consentendo sdi generare un elenco di stringhe con la proprietà specificata). Il più vecchio non lo è (va in un ciclo infinito), ma è a causa del metodo golf che ho usato per garantire che C sia non vuoto; se riscrivi il programma per specificare esplicitamente C come non vuoto, genera stringhe della forma "aa", "aabb", "aabbcc" e così via (Prolog essendo Prolog, non specifica le identità per i caratteri che le rendono in alto, solo una specifica di quali personaggi sono uguali). Il più recente genera stringhe della forma "aa", "abab", "abcabc" e così via; questo è un loop infinito a sé stante, e quindi non raggiunge mai il punto in cui si bloccherebbe a causa della mancata rilevazione di una stringa di lunghezza zero.


1

Brainfuck, 177 byte

+[<<<<,]>>>>[>+[>+[[>>]<+<[<<]>+>-]<[>+<-]>>>,>>[>>]+<<[<+>>-<-]<[>+<-]>>[,>[-<<
<<]<[<<<<]>]<[[<<]>]>>]>>[[>+>>>]>>>[>]<<<<[>+[-<<<,<]<[<<<[[<<<<]>>]<]>]>>]<[[-
>>>>]>>[<]<]<<]<.

formattato:

+[<<<<,]
>>>>
[
  >+
  [
    >+
    [
      [>>]
      <+<[<<]
      >+>-
    ]
    <[>+<-]>
    >>,>>[>>]
    +<<[<+> >-<-]
    <[>+<-]>
    >
    [
      not equal
      ,>[-<<<<]
      <[<<<<]
      >
    ]
    <
    [
      equal
      [<<]
      >
    ]
    >>
  ]
  >>
  [
    mismatch
    [>+>>>]
    >>>[>]
    <<<<
    [
      backtrack
      >+[-<<<,<]
      <
      [
        not done yet
        <<<
        [
          [<<<<]
          >>
        ]
        <
      ]
      >
    ]
    >>
  ]
  <
  [
    match
    [->>>>]
    >>[<]
    <
  ]
  <<
]
<.

Prevede input senza una nuova riga finale. Stampa \x00per falso e \x01vero.

Provalo online.

Questo implementa la ricerca approfondita. In particolare: verifica la presenza di prefissi ripetuti di lunghezza crescente a partire dal suffisso corrente, quindi passa al suffisso successivo se viene trovata una corrispondenza, altrimenti torna indietro.

All'inizio, la stringa viene invertita e una sentinella \x01viene posizionata alla fine.

Il nastro è diviso in nodi a 4 celle. Il layout di memoria di un nodo è:

c h x 0

dove si ctrova il personaggio, hè una bandiera per indicare se il personaggio si trova nella prima metà di un prefisso ripetuto ed xè una bandiera per tenere traccia dell'attuale coppia di caratteri da confrontare. Le hbandiere rimangono in posizione mentre le xbandiere formano una finestra mobile.

Se la stringa è accoppiabile, il puntatore si posiziona accanto alla sentinella alla fine del ciclo principale; in caso contrario, il puntatore cade dal lato sinistro della stringa durante il backtracking.


1

Brachylog , 5 byte

~c~jᵐ

Provalo online!

Si noti che questo algoritmo può richiedere molto tempo, soprattutto in casi falsi, poiché controlla ogni possibile partizione della stringa di input.

Spiegazione

~c     Reversed concatenate: find a list that, when concatenated, results in the input string
       This examines all partitions of the input
  ~jᵐ  Map reversed juxtapose: for each string in that list, is it the result of concatenating
       a string to itself?

Per una stringa di input come "ababcc", ~cprova diverse partizioni fino a quando non arriva ["abab", "cc"], a quel punto ha ~jsuccesso per entrambi gli elementi dell'elenco, gli output ["ab", "c"]e il predicato ha esito positivo.


1

R , 31 byte

grepl("^((.+)\\2)+$",scan(,""))

Provalo online!

Basato sulla risposta Retina.

R , 129 byte

Ed ecco una risposta originale, non regex:

o=(y=utf8ToInt(scan(,"")))<0;for(i in 2*1:(sum(y>0)/2))for(j in 1:(i/2)){w=i:(i-j+1);v=w-j;if(all(y[w]==y[v]))o[c(v,w)]=T};all(o)

Provalo online!


0

Lithp , 57 caratteri

#S::((? (!= (null) (match S "^((.+)\\2)+$")) true false))

Esempio di utilizzo:

% pairable_strings.lithp
(
    (def f #S::((? (!= (null) (match S "^((.+)\\2)+$")) true false)))
    (print (f "aa"))
    (print (f "aabaaababbbaba"))
    (print (f "aaababbabbabbbababbaabaabaababaaba"))
    (print (f "ba"))
)

# ./run.js pairable_strings.lithp
AtomValue { value: 2, type: 'Atom', name: 'true' }
AtomValue { value: 2, type: 'Atom', name: 'true' }
AtomValue { value: 2, type: 'Atom', name: 'true' }
AtomValue { value: 3, type: 'Atom', name: 'false' }
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.