Sequenza look-and-say: edizione numeri romani


20

Descrizione della sfida

Abbiamo avuto alcune sfide che coinvolgono la sequenza Look-and-say . Promemoria rapido:

  • La sequenza inizia con 1,
  • I termini successivi di questa sequenza sono generati elencando ogni gruppo di cifre ripetute nel termine precedente,

Quindi i primi termini sono:

1        "one"
11       "one one" (we look at the previous term)
21       "two ones"
1211     "one two, one one"
111221   "one one, one two, two ones"
312211   "three ones, two twos, one one"

Ora facciamo la stessa cosa, ma utilizziamo invece i numeri romani . Iniziamo con Ie seguiamo le stesse regole (applichiamo invece la regola di conteggio delle cifre ai caratteri, quindi leggiamo IVXcome one one, one five, one tenanziché one four, one teno in altro modo):

I           "one"
II          "one one"
III         "two ones" = "II" + "I"
IIII        "three ones" = "III" + "I"
IVI         "four ones" = "IV" + "I"
IIIVII      "one one, one five, one one"
IIIIIVIII   "three ones, one five, two ones" = ("III" + "I") + ("I" + "V") + ("II" + "I")

Dato un numero intero positivo N, sia:

  • Emette i primi Nnumeri di questa sequenza (anche qualsiasi separatore ragionevole va bene["I", "II", "III", ...]
  • Emette Nil termine di questa sequenza (può essere indicizzato 0).

Ricorda di rendere il tuo codice il più breve possibile, poiché questa è una sfida di !

EDIT: credo che ci sia sempre un modo standard / preferito di esprimere numeri interi come numeri romani, (come 95-> XCVinvece di VC). Coppia di convertitori di numeri romani che ho trovato online confermano la mia opinione. In caso di dubbio, utilizzare un convertitore online , poiché l'elenco di tutti i casi limite e le regole specifiche per la scrittura di numeri romani non è il punto di questa sfida.

EDIT2: @PeterTaylor e @GregMartin sottolineato che solo i numeri minore o uguale a 5comparire nella sequenza, in modo da non dovete preoccuparvi di l'ambiguità di numeri romani (numeri 1- 8sono I, II, III, IV, V, VI, VII, e VIII)


Non esiste un'espressione numerica romana unica per ogni numero intero. Quali numeri potrebbe essere necessario esprimere e quali espressioni di quei numeri sono valide?
Peter Taylor,

Cosa intendi con "non esiste un'espressione numerica romana unica per ogni numero intero"? Ti piace 4/ IV/ IIII? Oppure 95/ XCV/ VC? Potrebbe non esserci sempre un modo unico per esprimere un numero intero, ma sono abbastanza sicuro che ce ne sia sempre uno preferito (standard): correggimi se sbaglio.
shooqie,

1
quanto lontano dobbiamo andare con i nostri numeri romani?
Maltysen,

Sì, entrambi questi casi. Nel secondo caso, penso che sia preferibile una questione di opinione.
Peter Taylor,

9
@shooqie se questi dettagli non fossero chiariti, come confronteresti le risposte? Se ci sono alcuni casi limite lasciati all'interpretazione, i punteggi effettivi diventano insignificanti perché potrebbero fare una differenza maggiore rispetto a qualsiasi trucchetto che potresti trovare.
Martin Ender,

Risposte:


17

Perl, 49 byte

Include +1 per -p

Esegui con l'indice basato su 0 su STDIN, ad es

ecce.pl <<< 14

ecce.pl:

#!/usr/bin/perl -p
s,(.)\1*,$&/$1%182 .$1,eg for($_=/$/)x$`;y;19;IV

Le formule magiche sono così magiche.

Normalmente ($_=//)x$'userei per accorciare il controllo del loop di un byte, ma il punteggio su questo sito dà un handicap di 2, quindi finisce 1 byte in più. Sui perl più vecchi puoi eliminare lo spazio prima for. Alcune versioni di perl ti costringono ad aggiungere un finale ;per chiudere la traslitterazione. Ma ciò che viene dato sopra è il codice che funziona sul mio sistema.

Spiegazione

Lavorare all'indietro dalla soluzione al codice:

Le trasformazioni di stringa di cui abbiamo bisogno:

I     -> II
II    -> III
III   -> IIII
IIII  -> IVI
IIIII -> VI

V     -> IV
VV    -> IIV

Ogni sostituzione termina con il carattere ripetuto. Otterrò una sequenza degli stessi personaggi usando regex /(.)\1*/, quindi questo può essere fatto aggiungendo $1. La parte prima del ->è in $&. Con ciò ho ancora bisogno di:

I     -> I
II    -> II
III   -> III
IIII  -> IV
IIIII -> V

V     -> I
VV    -> II

Scrivi Icome 1e Vcome 9:

1     -> 1
11    -> 11
111   -> 111
1111  -> 19
11111 -> 9

9     -> 1
99    -> 11

Dividendo la parte precedente ->per la cifra ripetuta questo diventa:

1     -> 1
11    -> 11
111   -> 111
1111  -> 19
11111 -> 9

1     -> 1
11    -> 11

Quindi ora l'originale ripetuto Vnon fa più eccezione. Quindi voglio un'espressione che lo faccia accadere:

1     -> 1
11    -> 11
111   -> 111
1111  -> 19
11111 -> 9

E questo può essere fatto con un semplice modulo 182:

1     % 182 = 1
11    % 182 = 11
111   % 182 = 111
1111  % 182 = 19
11111 % 182 = 9

(questo arriva anche IIIIIIa VIdestra anche se qui non è necessario)

Non resta che inizializzare la variabile di lavoro su 1per l'indice 0, ripetere questa trasformazione in un ciclo e alla fine sostituire 1con Ie 9conV

1, 9ed 182è l'unica combinazione di parametri per cui funziona questa semplice formula.


2
Questo è geniale! :)
Lynn,

10

Mathematica, 113 90 83 byte

Grazie a Martin Ender per i suggerimenti che hanno ridotto la lunghezza di oltre il 25%!

Mostra i comandi di alto livello in Mathematica.

Nest[Flatten[Characters@{RomanNumeral@#,#2}&@@@Reverse@@@Tally/@Split@#]&,{"I"},#]&

Una funzione pura, che prende un argomento N e produce l'ennesimo elemento di questa sequenza (indicizzata 0), come un elenco di caratteri. Distribuire un po ':

Nest[
  Flatten[
    Characters @ {RomanNumeral@#,#2}& @@@
      Reverse @@@ Tally /@ Split@ #
    ]& ,
  {"I"}, #]&

L'esterno Nestesegue l'iterazione della funzione a quattro righe centrale, iniziando da {"I"}N volte. La riga 4 divide l'elenco dei caratteri del numero romano di input in serie di caratteri simili, conta ogni serie Tallye mette i conteggi prima dei caratteri che contano. La riga 3 rende i conteggi come numeri romani, quindi li divide in elenchi di caratteri. Il Flattencomando riduce l'intero elenco di elenchi a un elenco unidimensionale.

Ecco la versione iniziale:

Nest[
  "" <> Flatten[{RomanNumeral@#[[1]], #[[2]]} & /@
    (Reverse@#[[1]] & /@ 
      Tally /@
        Split@Characters@#)] &,
  "I", #] &

3
Grrr Mathematica;)
Decadimento beta

Se usi al @@@posto /@tuo puoi usare #e #2invece di #[[1]]e #[[2]]. Inoltre, gli elenchi di caratteri sono tipi di stringa accettabili, quindi puoi lavorare con quelli ed evitare di usarli Characters@.
Martin Ender,

@MartinEnder Aha, sapevo che doveva esserci stata una @@@scorciatoia simile! Per quanto riguarda gli elenchi di caratteri che sono tipi di stringa accettabili (che sono d'accordo accorcerei il codice): c'è un post su questo sito che mi puoi indicare che descrive gli standard della comunità?
Greg Martin,


1
Qualche risparmio in più: i Charactersthread automaticamente che puoi usare @, Reverse@#&ovviamente sono gli stessi del semplice Reverse, nel qual caso non hai bisogno di quelle parentesi. E la notazione con prefisso (nel caso di Flatten) non salva nulla se è necessario aggiungere parentesi per farlo funzionare. Combinando tutti questi:Nest[Flatten[Characters@{RomanNumeral@#,#2}&@@@Reverse@@@Tally/@Split@#]&,{"I"},#]&
Martin Ender,

8

CJam ( 33 30 byte)

"I"{e`{(4md1$^'I*\'V*@}%e_}ri*

Demo online

La chiave della correttezza dell'implementazione è il seguente teorema:

Se la prima generazione è I, nessuna lunghezza della corsa è mai maggiore di cinque

Lemma: se la prima generazione è I, nessuna stringa contiene mai VVV. La prova è per contraddizione. Supponiamo che esista un primo indice nper il quale ncontiene la th generazione VVV. Se ciò si VVVinterrompe come (a)V VVallora la conversione dalla generazione precedente è cattiva: avrebbe dovuto essere (a+5)V. Quindi deve essere VV V(d), e contenuta la generazione precedente VVVVV, contraddire la scelta di n.

Supponiamo ora che esista un primo indice mper il quale mcontiene la th generazione ...IIIIII.... Si noti che non possono esserci cifre diverse da Ie Vnella stringa, poiché nessuna generazione precedente ha avuto una corsa di nove Isecondi o nove Vsecondi. Al massimo quattro delle Is provengono da una corsa di Is nella stringa precedente, per cui la sezione corrispondente della stringa precedente occorre ...IIIVV...dando ... IIII IIV .... Dato che la VVgenerazione in generazione m-1non proviene da VVVVV(vedi lemma), la seconda Vdeve essere una lunghezza di cifre I, quindi in generazione m-1abbiamo ...IIIVVI.... E dal momento che vogliamo che le Is iniziali diano IIIIe non IVIoVI, è preceduto o dall'inizio della stringa o da a V.

Se abbiamo (...V)?IIIVVI...nella generazione m-1, cosa abbiamo nella generazione m-2? Abbiamo già osservato che il VVgen. m-1deve essere analizzato come (a)V V(I).

Supponiamo di prendere a=2: (...V)?I IIV VI...In realtà deve essere ...VI IIV VI..., anche se quella guida Vpotrebbe far parte IV; quindi nella generazione precedente abbiamo (...V)? IIII VV IIIII...o (...V)? IIIII VV IIIII. In entrambi i casi ci troviamo in difficoltà VVIIIII: la seconda Vdeve essere una lunghezza della corsa, ma ...VI IIII...richiede quindi una coppia successiva (lunghezza della corsa, cifra) con la stessa cifra.

Quindi deve essere a=1: (...V)?II IV VI.... Poiché la generazione mè la prima con una corsa di sei Isecondi, deve essere (...V)? II IV VI...così, così m-2è la generazione (...V)? I V IIIII.... ...VIVIIIII...è impossibile: tuttavia scegliamo di interpretare il secondo Vfinendo con due coppie consecutive (lunghezza, cifra) con la stessa cifra.

Pertanto, la generazione m-2deve essere ^IVIIIII...analizzata come ^IV IIII I(V)...o ^IV III II(V).... Questi danno rispettivamente generazione m-3come ^V III V ...o ^V II VV....

Ma se guardiamo l'inizio delle stringhe che iniziano con la prima che inizia con V, otteniamo un ciclo:

    VI IV I...
    IV III IV ...
    II IV IVI ...
    IIII IV II IV ...

e quindi nessuna generazione inizia mai con VIIIVo VIIVV. Dobbiamo concludere che non esiste m.

Dissezione

"I"          e# Initial generation
{            e# Loop...
  e`         e#   Run-length encode
  {          e#   Foreach [run-length char] pair...
    (        e#     Extract the run-length r
    4md1$^   e#     Get the number of Vs and the number of Is
             e#     The number of Vs is r/4 ; the number of Is is (r%4)^(r/4)
    'I*\'V*@ e#     Repeat strings the appropriate number of times and reorder
  }%
  e_         e#  Flatten to a simple string
}ri*         e# ... n times, where n is taken from stdin

6

Python 3, 195 byte

Ci sono molti byte sprecati sui numeri romani, quindi probabilmente c'è da giocare a golf lì.

Grazie a @ El'endiaStarman, @ Sherlock9 e @Shooqie

import re
def f(x,r=""):
 for v,i in(5,"V"),(4,"IV"),(1,"I"):a,x=divmod(x,v);r+=i*a
 return r
s="I"
for i in[0]*int(input()):print(s);s=re.sub(r'(.)\1*',lambda m:f(len(m.group()))+m.group()[0],s)

Ideone esso!


Puoi omettere le parentesi quadre:for v,i in(5,"V"),(4,"IV"),(1,"I")
shooqie

@shooqie Non avevo idea che tu potessi farlo: D
Decadimento beta

for v,i in(5,"V"),(4,"IV"),(1,"I"):a,x=divmod(x,v);r+=i*asalva un byte.
Sherlock9,

@ βετѧΛєҫαγ: Inoltre, non sembra che tu stia utilizzando i(come in for i in range(...)). Ho provato a dilettarmi, execma questo è sfuggito 1al metodo 'sub' sembra incasinare il codice, non sono stato in grado di trovare una soluzione alternativa.
shooqie,

@shooqie ho accorciato un po 'per sbarazzarsi dirange
Decadimento Beta

4

R, 110 107 byte

as.romancombinato con rlerende questo facile. L'abuso di scoping e il comportamento del gatto incorporato <<-salvano pochi byte.

x="I"
replicate(scan(),{r=rle(strsplit(x,"")[[1]])
x<<-paste(rbind(paste(as.roman(r$l)),r$v),collapse="")})

Accetta N dalla console. Emette i primi 2 a N termini della sequenza (che credo rientri nelle specifiche ...)

 [1] "II"                                                                                                                                                                                                                                     
 [2] "III"                                                                                                                                                                                                                                    
 [3] "IIII"                                                                                                                                                                                                                                   
 [4] "IVI"                                                                                                                                                                                                                                    
 [5] "IIIVII"                                                                                                                                                                                                                                 
 [6] "IIIIIVIII"                                                                                                                                                                                                                              
 [7] "VIIVIIII"                                                                                                                                                                                                                               
 [8] "IVIIIIVIVI"                                                                                                                                                                                                                             
 [9] "IIIVIVIIVIIIVII"                                                                                                                                                                                                                        
[10] "IIIIIVIIIVIIIIVIIIIIVIII"                                                                                                                                                                                                               
[11] "VIIVIIIIIVIVIIVVIIVIIII"                                                                                                                                                                                                                
[12] "IVIIIIVVIIVIIIVIIIIIVIIIIVIVI"                                                                                                                                                                                                          
[13] "IIIVIVIIIVIIIIVIIIIIVVIIVIVIIVIIIVII"                                                                                                                                                                                                   
[14] "IIIIIVIIIVIIIIIVIVIIVVIIIVIIIIVIIIVIIIIVIIIIIVIII"                                                                                                                                                                                      
[15] "VIIVIIIIIVVIIVIIIVIIIIIVIIIIIVIVIIVIIIIIVIVIIVVIIVIIII"                                                                                                                                                                                 
[16] "IVIIIIVVIIIVIIIIVIIIIIVVIIVVIIVIIIVIIIIVVIIVIIIVIIIIIVIIIIVIVI"                                                                                                                                                                         
[17] "IIIVIVIIIVIIIIIVIVIIVVIIIVIIIIIVIIIIVIIIIIVIVIIIVIIIIVIIIIIVVIIVIVIIVIIIVII"                                                                                                                                                            
[18] "IIIIIVIIIVIIIIIVVIIVIIIVIIIIIVIIIIIVVIIVIVIIVVIIVIIIVIIIIIVIVIIVVIIIVIIIIVIIIVIIIIVIIIIIVIII"                                                                                                                                           
[19] "VIIVIIIIIVVIIIVIIIIVIIIIIVVIIVVIIIVIIIIVIIIVIIIIIVIIIIVIIIIIVVIIVIIIVIIIIIVIIIIIVIVIIVIIIIIVIVIIVVIIVIIII"                                                                                                                              
[20] "IVIIIIVVIIIVIIIIIVIVIIVVIIIVIIIIIVIIIIIVIVIIVIIIIIVVIIVIVIIVVIIIVIIIIVIIIIIVVIIVVIIVIIIVIIIIVVIIVIIIVIIIIIVIIIIVIVI"                                                                                                                    
[21] "IIIVIVIIIVIIIIIVVIIVIIIVIIIIIVIIIIIVVIIVVIIVIIIVIIIIVVIIIVIIIIVIIIVIIIIIVIIIIIVIVIIVVIIIVIIIIIVIIIIVIIIIIVIVIIIVIIIIVIIIIIVVIIVIVIIVIIIVII"                                                                                             
[22] "IIIIIVIIIVIIIIIVVIIIVIIIIVIIIIIVVIIVVIIIVIIIIIVIIIIVIIIIIVIVIIIVIIIIIVIVIIVIIIIIVVIIVVIIVIIIVIIIIIVIIIIIVVIIVIVIIVVIIVIIIVIIIIIVIVIIVVIIIVIIIIVIIIVIIIIVIIIIIVIII"                                                                      
[23] "VIIVIIIIIVVIIIVIIIIIVIVIIVVIIIVIIIIIVIIIIIVVIIVIVIIVVIIVIIIVIIIIIVVIIVIIIVIIIIVVIIIVIIIIIVIIIIVIIIIIVVIIVVIIIVIIIIVIIIVIIIIIVIIIIVIIIIIVVIIVIIIVIIIIIVIIIIIVIVIIVIIIIIVIVIIVVIIVIIII"                                                   
[24] "IVIIIIVVIIIVIIIIIVVIIVIIIVIIIIIVIIIIIVVIIVVIIIVIIIIVIIIVIIIIIVIIIIVIIIIIVVIIIVIIIIVIIIIIVIVIIIVIIIIIVVIIVIVIIVVIIIVIIIIIVIIIIIVIVIIVIIIIIVVIIVIVIIVVIIIVIIIIVIIIIIVVIIVVIIVIIIVIIIIVVIIVIIIVIIIIIVIIIIVIVI"                             
[25] "IIIVIVIIIVIIIIIVVIIIVIIIIVIIIIIVVIIVVIIIVIIIIIVIIIIIVIVIIVIIIIIVVIIVIVIIVVIIIVIIIIIVIVIIVVIIVIIIVIIIIIVVIIIVIIIIVIIIVIIIIIVIIIIIVVIIVVIIVIIIVIIIIVVIIIVIIIIVIIIVIIIIIVIIIIIVIVIIVVIIIVIIIIIVIIIIVIIIIIVIVIIIVIIIIVIIIIIVVIIVIVIIVIIIVII"

1

JavaScript (ES6), 107

Funzione ricorsiva che restituisce l'ennesimo termine in base 0

f=(n,r='I')=>n?f(n-1,r.match(/I+|V+/g).map(x=>((n=x.length)-4?'VIII'.slice(n<5,1+n%5):'IV')+x[0]).join``):r

Test

f=(n,r='I')=>n?f(n-1,r.match(/I+|V+/g).map(x=>((n=x.length)-4?'VIII'.slice(n<5,1+n%5):'IV')+x[0]).join``):r

function update() {
  O.textContent=f(I.value)
}

update()
<input id=I value=25 type=number oninput='update()'><pre id=O></pre>


1

Perl 6 , 62 byte

{("I",{S:g/(.)$0*/{<I II III IV V>[$/.chars-1]~$0}/}...*)[$_]}

Funzione anonima che accetta un indice in base zero.

Si avvale del fatto che non sono necessari numeri romani superiori a 5, poiché gli unici gruppi di cifre ripetute che possono verificarsi sono:

I     -> II
II    -> III
III   -> IIII
IIII  -> IVI
IIIII -> VI

V     -> IV
VV    -> IIV

( provalo online )

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.