Oryginalny numer (II)


18

To wyzwanie jest zasadniczo identyczne z tym z tą tylko różnicą: teraz można tasować litery w dowolnym miejscu ciągu.

Scenariusz

John ma ważną liczbę i nie chce, aby inni ją widzieli.

Postanowił zaszyfrować numer, wykonując następujące czynności:

Jego liczba jest zawsze ciągiem malejącym (tj. "1123")

Przekształcił każdą cyfrę w angielskie słowa. (tj. "123" -> "ONETWOTHREE")

A następnie, losowo ułóż litery. (tj. "ONETWOTHREE" -> "EEWOOHRNTET")

John czuł, że jego liczba jest w tym bezpieczna. W rzeczywistości takie szyfrowanie można łatwo odszyfrować :(


Zadanie

Biorąc pod uwagę zaszyfrowane ciągi, Twoim zadaniem jest odszyfrowanie go i zwrócenie oryginalnego numeru.


Zasady

  • To jest kod golfowy, więc wygrywa najkrótsza odpowiedź w bajtach
  • Możesz założyć, że ciąg wejściowy jest zawsze poprawny
  • Łańcuch wejściowy zawiera tylko wielkie litery
  • Oryginalne numery są zawsze ułożone w porządku rosnącym
  • Możesz zwrócić liczbę w formacie ciągu lub liczby całkowitej
  • Litery będą tasowane tylko między jednym słowem, a nie między całym ciągiem.Litery można tasować w dowolnym miejscu ciągu.
  • Liczby będą tylko od 1 do 9 włącznie ( ONEdo NINE)

Możliwy nieszyfrowany ciąg

Oto lista ciągów zaraz po ich przekonwertowaniu na ciągi z liczb:

 1 -> ONE 
 2 -> TWO
 3 -> THREE
 4 -> FOUR
 5 -> FIVE
 6 -> SIX
 7 -> SEVEN
 8 -> EIGHT
 9 -> NINE

Przykłady

"NEO" -> 1

"NWEOOT" -> 12

"TOEERWNEHOT" -> 123

"IHNEVGENNEISTE" -> 789

"WEETVTRFSVUHNEEFRHIXEOINSNIEGTOONIEE" -> 123456789

"EWHEWROETOTTON" -> 1223

"ONEWESTV" -> 27 (dzięki, ETHproductions!)


7
Sugerowany przypadek testowy: coś takiego "ONEWESTV" -> 27(zawiera liczbę, która tak naprawdę się nie pojawia)
ETHproductions

@ETHproductions Świetny pomysł! Dodany.
Cristian Lupascu

Dlaczego nie ma „ZERO”?
RosLuP

@RosLuP John nienawidzi zer wiodących ...
Cristian Lupascu

Odpowiedzi:


9

Python 2 , 123 bajty

c=map(input().count,"OWHUFXSGIQ")
i=4
for j in"71735539994":c[i*2]-=c[int(j)];i=-~i%5
s=""
for n in c:i+=1;s+=`i`*n
print s

Pełny program pobierający cytowane dane i wypisujący numer Johna.

Wypróbuj online! lub zobacz zestaw testowy

W jaki sposób?

Pracujmy z przykładem „NEONSEXTOWNII” (aby uzyskać 1269, i być nieco Leisure Suite Larry -esque!)

Najpierw c=map(input().count,"OWHUFXSGIQ")pobiera dane wejściowe i liczy liczbę każdego z OWHUFXSGIQnich - są to litery, które pojawiają się w każdej liczbie w porządku rosnącym, przy czym 2,4,6 i 8 mają „własne” litery ( WUXG) oraz dodatkową literę, Qaby dodać zero do końca i wyrównaj długość wynikowej listy. Na przykład:

[2,1,0,0,0,1,1,0,2,0] <- c
 O W H U F X S G I Q  <- is the counts of these letters
 1 2 3 4 5 6 7 8 9 0  <- which "relate to" these digits in John's number
   2   4   6   8   0  <- these will be correct as the letters are unique to their words

Wpisy 1, 3, 5, 7 i 9 wymagają dostosowania, aby poprawić liczebność pozostałych liter. Jest to wykonywane przez następną pętlę:

i=4
for j in"71735539994":c[i*2]-=c[int(j)];i=-~i%5

Zauważ, że wpisy do dostosowania są naprzemiennymi (1,3,5,7,9,1,3,5, ...), więc możemy dodać dwa do zmiennej indeksu na każdym kroku i modulo o 10, aby pozostać w zasięg, jeśli musimy przejść więcej niż jeden raz (co robimy). Aby zaoszczędzić niektóre bajty, możemy zwiększyć o jeden i modulo o 5 i użyć podwójnego indeksu.
Ponieważ korekty dla 9 wymagają najwięcej pracy, zaczynamy od tego - znajduje się ona w indeksie 8, więc zaczynamy od i=4. Łańcuch "71735539994"podaje następnie indeksy jwartości, które należy usunąć na każdym etapie (gdzie zapewniliśmy, że dziewiąty indeks będzie zawierał zero przy użyciu "Q"podczas tworzenia c); c[i*2]-=c[int(j)]wykonuje każdy indywidualny regulację i i=-~i%5przenosi ido następnego wskaźnika (gdzie -~ijest -(-1-i)lub i+1zapisywanie nawiasach (i+1)%5) utrzymująci*2 w granicach c.
W ten sposób najpierw odejmujemy liczbę w indeksie j=7od liczby w indeksie i*2=8, odejmując liczbę „G” zliczoną od liczby „I”, dostosowując odliczanie „NINE” o (poprawną) liczbę „Ośmiu” ( który ma również „I”). Następnie przechodzimy do i=0( -~4%5 = (4+1)%5 = 0), odwołując się do indeksu, i*2 = 0który jest dla „JEDNEJ”, i odejmujemy wartość znalezioną przy indeksie j=1wpisu zliczającego „W”, a zatem „DWIE”, dostosowując liczbę „O” w dół. Pod koniec pętli mamy poprawione liczby:

[1,1,0,0,0,1,0,0,1,0] <- c   (for 1223333448 it would be: [1,2,4,2,0,0,0,1,0,0])
 1 2 3 4 5 6 7 8 9 0

więc pozostaje tylko wydrukować to, co cteraz reprezentuje ( 1269). ijest teraz z powrotem na 0, więc zwiększamy go na początku pętli i używamy jako naszej cyfry:

s=""
for n in c:i+=1;s+=`i`*n
print s

Tylne tiki, `i`są skrótem Python2, dla repr(i)którego pobiera ciąg znaków reprezentujący obiekt (dany znak cyfry jako ciąg) i pomnożenie łańcucha przez liczbę tworzy nowy ciąg z wielu powtórzeń (tutaj pokazujemy tylko n=0odwrócenie `i`od powiedz "5"do ""i n=1obracając utrzymanie powiedzenia "6"jak "6", ale działa również dla większych liczb całkowitych dodatnich, więc "3"*4staje się "3333"na przykład).


8

05AB1E , 31 bajtów

[{‘Z€µ‚•„í†ìˆÈŒšï¿Ÿ¯¥Š‘#NSèJ{Q#

Wypróbuj online!

Wyjaśnienie

[                                   # start loop
 {                                  # sort input
  ‘Z€µ‚•„í†ìˆÈŒšï¿Ÿ¯¥Š‘#            # push the list ['Z','ONE','TWO','THREE','FOUR','FIVE','SIX','SEVEN','EIGHT','NINE']
                        N           # push the current iteration counter
                         S          # split to list of digits
                          è         # index into the list with each
                           J{       # join to string and sort
                             Q#     # if the strings are equal, exit loop
                                    # implicitly print iteration counter

Bardzo nieefektywny przy dużych nakładach.


‘Z€µ‚•„í†ìˆÈŒšï¿Ÿ¯¥Š‘# # push the list ['Z','ONE','TWO','THREE','FOUR','FIVE','SIX','SEVEN','EIGHT','NINE']: czy możesz trochę wyjaśnić, staram się zrozumieć, w jaki sposób można wygenerować dowolny ciąg.
Cyril Gandon

1
@CyrilGandon: ogranicza skompresowany ciąg wielkich liter słów oddzielonych spacjami. Zśrodki Z. Wszystkie pozostałe pary 2-symbolowe oznaczają skompresowane słowo ze słownika 05AB1E . Na przykład €µtłumaczy się jako ONE.
Emigna

Fajnie, jak skompresujesz ciąg znaków w słowniku? Coś z wartością Unicode pary?
Cyril Gandon

1
@CyrilGandon: Bierzesz numer wiersza słowa w słowie (2420 na powitanie ) i odejmujesz 1. To daje nam 2419. Symbole musimy są symbole, które są następnie 24i 19w Dokumentach . W naszym przypadku jest to 24=Ÿi 19=™tak HELLObyłoby‘Ÿ™‘
Emigna

1
Istnieje również kompresor napisany przez Adnana, którego można używać w większości przypadków. Link jest nieco długi, ale można go znaleźć w czacie 05AB1E . To również dobre miejsce, aby zapytać, czy masz jakieś pytania :)
Emigna

8

Retina , 112 97 bajtów

O`.
}`GH
8
X
6
H
3
+`F(.*)O(.*)U
4$1$2
+`O(.*)W
2$1
+`F(.*)V
5$1
+`N(.*)V
7$1
}`NO
1
NN
9
T`L
O`.

Wypróbuj online!

-12 bajtów dzięki @Neil

-3 bajty przy użyciu klas L znaków w transpozycji

Jak to działa

Zasadniczo polega to na tym, że litery są używane tylko w niektórych nazwach numerów. Na przykład SIXjest jedyną nazwą zawierającą X. Staje się to trudniejsze z uwagi na fakt, że niektóre słowa nakładają się na litery, na przykład oba FIVEi SEVENza pomocą V. Można to poprawić, identyfikując się FIVEz F(.*)V.


1
@ RickHitchcock Naprawiono. Rekurencja po konwersji na 8 nie działała poprawnie
fireflame241

1
@RickHitchcock. Naprawiono rekurencję dla nich wszystkich.
fireflame241

Irytujące GHi NObędą przylegać, z wyjątkiem wszelkich poprzednich 8lub 1wcześniejszej zmiany ...
Neil

Być }`GH 8może zadziałałoby 8- }spowodowałoby to, że postacie zostałyby ponownie posortowane, w ten sposób umieszczając wszystkie pozostałe Gi Hrazem.
Neil

@Neil Fajny pomysł. Byłem też w stanie to zrobić NO -> 1, co było wygodne.
fireflame241

5

Kotlin 1.1 , 359 352 331 327 325 bajtów

Zgłoszenie

fun r(r:String):String{var s=""
val f=r.split(s).groupingBy{it}.eachCount()
val c=Array(10,{0})
c[8]=f["G"]?:0
c[6]=f["X"]?:0
c[4]=f["U"]?:0
c[2]=f["W"]?:0
c[1]=(f["O"]?:0)-c[2]-c[4]
c[3]=(f["R"]?:0)-c[4]
c[7]=(f["S"]?:0)-c[6]
c[5]=(f["V"]?:0)-c[7]
c[9]=((f["N"]?:0)-c[1]-c[7])/2
for(i in 1..9)for(x in 1..c[i])s+=i
return s}

Nie działa na TryItOnline, ponieważ Kotlin 1.1 nie jest obsługiwany

Test

fun r(r:String):String{
val f=r.split("").groupingBy{it}.eachCount()
val c=Array(10,{0})
c[8]=f["G"]?:0
c[6]=f["X"]?:0
c[4]=f["U"]?:0
c[2]=f["W"]?:0
c[1]=(f["O"]?:0)-c[2]-c[4]
c[3]=(f["R"]?:0)-c[4]
c[7]=(f["S"]?:0)-c[6]
c[5]=(f["V"]?:0)-c[7]
c[9]=((f["N"]?:0)-c[1]-c[7])/2
var s=""
for(i in 1..9)for(x in 1..c[i])s+=i
return s}

data class TestData(val input: String, val output: String)

fun main(vararg args:String) {
    val items = listOf(
    TestData("NEO" , "1"),
    TestData("NWEOOT" , "12"),
    TestData("TOEERWNEHOT" , "123"),
    TestData("IHNEVGENNEISTE" , "789"),
    TestData("WEETVTRFSVUHNEEFRHIXEOINSNIEGTOONIEE" , "123456789"),
    TestData("EWHEWROETOTTON" , "1223")
    )
    for (item in items) {
        val out = r(item.input)
        if (out != item.output) {
            throw AssertionError("Bad result: $item : $out")
        }
    }
}

Logika

Prześcieradło

Użyłem powyższego arkusza, aby znaleźć najprostszy sposób rozwiązania każdej litery

  • Zielony = Rozwiąż sam
  • Niebieski = Potrzebuje zieleni do rozwiązania
  • Pomarańczowy = Potrzebuje bluesa do rozwiązania
  • Czerwony = Potrzebuje pomarańczy do rozwiązania

Edycje

  • -7 - Zmiany białych znaków przez w0lf
  • -21 - Skróć listę do tablicy
  • -4 - Usunięto niepotrzebne wsporniki
  • 0 - Dodano logikę
  • -2 - Ponowne użycie pustego łańcucha dzięki kevin-cruijssen

1
Właśnie zauważyłem, że jestem ściśle związany z tobą moją odpowiedzią Java 8 (127 bajtów), stosując podobne podejście. ;) Ale jedno pytanie: nie można zmienić var s=""i return sdo r=""i return rpoprzez ponowne wykorzystanie wejścia-String, które nie są już potrzebne w tym punkcie? Nigdy wcześniej nie programowałem w Kotlinie, więc być może mówię tu bzdury. ; p
Kevin Cruijssen


1
Ach tak, to oczywiście była możliwość; parametry są finaldomyślnie. Hmm, jeszcze jedna rzecz, w którą możesz grać w golfa: umieść var s=""pierwszą metodę i zastąp val f=r.split("").val f=r.split(s).. Znów nie mam pojęcia, czy to działa. Szkoda, że ​​TIO nie obsługuje jeszcze wersji 1.1, w przeciwnym razie sam bym wypróbował te sugestie, zanim
zabrzmię

4

Galaretka , 37 bajtów

1ðDị“©ȯ¿w¶&ÇhṆỌƘ#Ȯʋ~¢CNẓ_»ŒuḲ¤ẎŒ!ċð1#

Wypróbuj online!

-1 dzięki Jonathan Allan .


Upływa limit czasu dla niektórych danych wejściowych dłuższych niż 7 znaków (np .: NINEFIVE, THREEFIVE). Czy to błąd, czy kod jest po prostu nieefektywny?
Cristian Lupascu,

@ w0lf the last ( Œ!oznacza „permutacje”)
Erik the Outgolfer

Zapisz bajt, używając „AA” zamiast „!”:...“©ȯ¿w¶&ÇhṆỌƘ#Ȯʋ~¢CNẓ_»...
Jonathan Allan

@JonathanAllan oh to AA to słowo?
Erik the Outgolfer

To pierwsze słowo w krótkim słowniku, tak.
Jonathan Allan

3

Java 8, 248 234 bajtów

s->{int x=0,a[]=new int[10];for(String t:"2WO;4UORF;6XSI;8GI;5FI;7S;3R;1O;9I".split(";"))for(;s.indexOf(t.charAt(1))>=0;a[t.charAt(0)-48]++)for(String z:t.split(""))s=s.replaceFirst(z,"");for(s="";x++<9;)for(;a[x]-->0;)s+=x;return s;}

Objaśnienie kodu:

s->{
    // Array to count how often which number appears
    int a[]=new int[10];
    // The first character behind the number serves the identification
    // the other characters get removed to identify the other numbers later
    for(String t:"2WO;4UORF;6XSI;8GI;5FI;7S;3R;1O;9I".split(";"))
        // Check if the string contains the id 
        for(;s.indexOf(t.charAt(1))>=0;a[t.charAt(0)-48]++)
            // Remove the relevant charcters
            for(String z:t.split(""))
                s=s.replaceFirst(z,"");
    // Clear the string to write the output
    s="";
    // write the numbers sequential into the output 
    for(int x=0;x++<9;)
        for(;a[x]-->0;)
            s+=x;
    return s;
}

-14 Dzięki Olivier Grégoire



2

Java 8, 346 345 344 336 327 bajtów

s->{int g=c(s+=" ","G"),u=c(s,"U"),w=c(s,"W"),x=c(s,"X"),f=c(s,"F")-u,h=c(s,"H")-g,v=c(s,"V")-f,o=c(s,"O")-u-w,i=c(s,"I")-f-x-g;return d(s=d(s=d(s=d(s=d(s=d(s=d(s=d(s=d("",o,1),w,2),h,3),u,4),f,5),x,6),v,7),g,8),n,9);}int c(String...s){return~-s[0].split(s[1]).length;}String d(String s,int i,int n){for(;i-->0;s+=n);return s;}

Wypróbuj tutaj.

Ogólne wyjaśnienie:

Patrzyłem na występowanie każdego znaku w alfabecie:

E 13357789
F 45
G 8
H 38
I 5689
N 1799
O 124
R 34
S 67
T 238
U 4
V 57
W 2
X 6
  • Po raz pierwszy liczony wszystkie wystąpienia znaków single-dopasowania: G=8; U=4; W=2; X=6.
  • Następnie wszystkie wystąpienia dwóch dopasowanych znaków, które również pasują do jednej z czterech wyżej, które można odjąć od ich liczby: F=5; H=3.
  • Potem zrobiłem to samo dla V=7(odejmując F=5).
  • Wtedy taka sama dla wszystkich trzech dopasowania znaków, które zostały pozostawione: O=1; N=9.
    • Ale ponieważ Nma dwa wystąpienia NINE, musiałem zrobić dodatkowy -1dla każdego wystąpienia N, więc użyłem I=9zamiast tego (odejmując trzy poprzednie dopasowania zamiast dwóch).

Objaśnienie kodu:

s->{                    // Method with String as parameter and return-type
  int g=c(s+=" ","G"),  //  Amount of 8s (and append a space to `s` first, for the .split)
      u=c(s,"U"),       //  Amount of 4s
      w=c(s,"W"),       //  Amount of 2s
      x=c(s,"X"),       //  Amount of 6s
      f=c(s,"F")-u,     //  Amount of 5s
      h=c(s,"H")-g,     //  Amount of 3s
      v=c(s,"V")-f,     //  Amount of 7s
      o=c(s,"O")-u-w,   //  Amount of 1s
      i=c(s,"I")-f-x-g; //  Amount of 9s
  return d(             //  Return the result by:
   s=d(
    s=d(
     s=d(
      s=d(
       s=d(
        s=d(
         s=d(
          s=d("",       //   Making the input String `s` empty, since we no longer need it
                 o,1),  //   Append all 1s to `s`
         w,2),          //   Append all 2s to `s`
        h,3),           //   Append all 3s to `s`
       u,4),            //   Append all 4s to `s`
      f,5),             //   Append all 5s to `s`
     x,6),              //   Append all 6s to `s`
    v,7),               //   Append all 7s to `s`
   g,8),                //   Append all 8s to `s`
  i,9);                 //   And then returning `s` + all 9s
}                       // End of method

int c(String...s){  // Separate method with String-varargs parameter and int return-type
                    //  `s[0]` is the input-String
                    //  `s[1]` is the character to check
  return~-s[0].split(s[1]).length;
                    //  Return the amount of times the character occurs in the String
}                   // End of separated method (1)

String d(String s,int i,int n){
               // Separate method with String and two int parameters and String return-type
  for(;i-->0;  //  Loop from the first integer-input down to 0
      s+=n     //   And append the input-String with the second input-integer
  );           //  End of loop
  return s;    //  Return the resulting String
}              // End of separated method (2)

1
Cholera, pomyślałbym, że dodanie do listy i sortowanie byłoby krótsze (to nie jest). Dobra robota!
Olivier Grégoire

1
No cóż, w końcu cię obezwładniłem , ale nie za bardzo;)
Olivier Grégoire


1

Python 3 , 225 bajtów

def f(s):
	r=[]
	for i,w in zip([2,4,6,8,3,5,7,1,9],["WTO","UFOR","XSI","GEIHT","HTREE","FIVE","VSEEN","ONE","NINE"]):
		while s.count(w[0]):
			r+=[i]
			for l in w:s="".join(s.split(l,1))
	return "".join(sorted(map(str,r)))

Wypróbuj online!

Prosto: najpierw usuń cyfry oznaczone konkretną literą.


1

Python 3 , 125 bajtów

lambda s:''.join(min(w)*(2*sum(map(s.count,w[:2]))-sum(map(s.count,w)))for w in"O1WU W2 H3G U4 F5U X6 S7X G8 IUFXG9".split())

Wypróbuj online!

Po przeczytaniu powiązanego wyzwania zdałem sobie sprawę, że jest to odmiana rozwiązania Python firmy mdahmoune , które samo opiera się na rozwiązaniu ES6 Draco18s , ale hej, przynajmniej straciliśmy dwa bajty.

Podobnie jak to rozwiązanie, obliczamy odpowiedź poprzez liniową kombinację liczby wystąpień niektórych liter. Krótko kodujemy kombinacje liniowe, pisząc je jako słowa, do których należy dodać dwie pierwsze litery, a następnie wszystko odjąć. Czasami potrzebna jest postać do wypełnienia pierwszych dwóch znaków; używamy tego, aby ukryć cyfrę, którą chcemy wyprowadzić (która nigdy nie pojawi się na wejściu, więc nie wpłynie na nasz algorytm), którą wyodrębniamy min.



1

Aksjomat, 351 bajtów

s:="GXUWRFVIONETHS";e:EqTable(CHAR,INT):=table();v:=[8,6,4,2,3,5,7,9,1];z:=[k for k in 1..46|prime?(k)];F(x,y)==>for i in 1..#x repeat y;F(z,e.(s.i):=z.i);t:=[1787026,2451,16445,5957,16036207,130169,20372239,495349,20677];h(a)==(r:=1;F(a,r:=r*e.(a.i));j:=[];F(v,while r rem z.i=0 repeat(r:=r quo t.i;j:=cons(v.i,j)));j:=sort j;k:=0;F(j,k:=k*10+j.i);k)

niepomentowane wyniki

s:="GXUWRFVIONETHS" -- tutte le lettere di ONE..NINE in ordine di importanza 
e:EqTable(Character,Integer):=table()
v:=[8,6,4,2,3,5,7,9,1]              -- numeri da controllare in quell'ordine di apparizione di v
z:=[k for k in 1..46|prime?(k)]     -- 14 numeri primi da associare a s
F(x,y)==>for i in 1..#x repeat y 
F(z,e.(s.i):=z.i)                   -- riempie la tavola associando numeri primi alle lettere "GXUW..."
t:=[1787026,2451,16445,5957,16036207,130169,20372239,495349,20677]  -- prodotto di numeri primi 1787026 dovrebbe essere HEIGHT
h(a)==
     r:=1 ;F(a,r:=r*e.(a.i))        -- calcola il numero associato alla stringa a
     j:=[];F(v,while r rem z.i=0 repeat(r:=r quo t.i;j:=cons(v.i,j)));j:=sort j  -- leva il nome dei numeri che man mano trova, aggiunge a j
     k:=0 ;F(j,k:=k*10+j.i)         -- costruisce il numero decimale k, da j vettore ordinato
     k                              -- ritorna tale numero k
------------------------------------------------------
(8) -> h("IHNEVGENNEISTE")
   (8)  789
                                                    Type: PositiveInteger
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.