Welchen Typ haben meine Suffixe?


10

Intro

Deshalb habe ich wieder meine Zeit damit verschwendet, nach Suffix-Sortieralgorithmen zu suchen und neue Ideen von Hand und im Code zu bewerten. Aber ich habe immer Mühe, mich an die Art meiner Suffixe zu erinnern! Können Sie mir sagen, welcher Typ meine Suffixe sind?

Ganz links was?

Viele Suffix-Sortieralgorithmen (SAIS, KA, meine eigene Daware) gruppieren Suffixe in verschiedene Typen, um sie zu sortieren. Es gibt zwei Grundtypen: S-Typ- und L-Typ- Suffixe. Suffixe vom Typ S sind Suffixe, die lexikographisch kleiner ( S maller) sind als das folgende Suffix und L-Typ, wenn sie lexikographisch größer sind ( L arger). Ein S-Typ ganz links ( LMS-Typ ) ist genau das: Ein S-Typ- Suffix, dem ein L-Typ- Suffix vorangestellt ist .

Das Besondere an diesen Suffixen vom Typ LMS ist, dass wir nach dem Sortieren alle anderen Suffixe in linearer Zeit sortieren können! Ist das nicht großartig?

Die Herausforderung

Angenommen, eine Zeichenfolge wird durch ein Sonderzeichen abgeschlossen, das kleiner als jedes andere Zeichen in dieser Zeichenfolge ist (z. B. kleiner als das Nullbyte). Geben Sie für jedes Suffix ein entsprechendes Zeichen aus.

Sie können frei wählen , welche Zeichen für welche Art zu verwenden , aber ich würde es vorziehen , L, S and *für L-, S- and LMS-typeso lange , wie sie alle druckbaren sind ( 0x20 - 0x7E).

Beispiel

Angesichts der String- mmiissiissiippiAusgabe (bei Verwendung L, S and *):

 LL*SLL*SLL*SLLL

Zum Beispiel ist das erste Lauf die Tatsache zurückzuführen, dass mmiissiissiippi$es lexikographisch größer ist als miissiissiippi$(das $repräsentiert das hinzugefügte Minimalzeichen):

L - mmiissiissiippi$ > miissiissiippi$
L - miissiissiippi$  > iissiissiippi$
* - iissiissiippi$   < issiissiippi     and preceeded by L
S - issiissiippi$    < ssiissiippi$
L - ssiissiippi$     > siissiippi$
L - siissiippi$      > iissiippi$
* - iissiippi$       < issiippi$        and preceeded by L
S - issiippi$        < ssiippi$
L - ssiippi$         > siippi$
L - siippi$          > iippi$
* - iippi$           < ippi$            and preceeded by L
S - ippi$            < ppi$
L - ppi$             > pi$
L - pi$              > i$
L - i$               > $

Einige weitere Beispiele:

"hello world" -> "L*SSL*L*LLL"
"Hello World" -> "SSSSL*SSLLL"
"53Ab§%5qS"   -> "L*SSL*SLL"

Tor

Ich bin nicht hier, um Peter Cordes zu ärgern (ich werde das irgendwann beim Stackoverflow tun); Ich bin nur sehr faul, das ist natürlich ! Die kürzeste Antwort in Bytes gewinnt.


Bearbeiten: Die Reihenfolge der Zeichen wird durch ihren Bytewert angegeben. Das heißt, vergleichen sollte wie C sein strcmp.

Edit2: Wie in den Kommentaren angegeben, sollte die Ausgabe für jedes Eingabezeichen ein einzelnes Zeichen sein. Obwohl ich davon ausgegangen bin, dass dies als "Rückgabe einer Zeichenfolge" verstanden wird, scheint mindestens 1 Antwort eine Liste einzelner Zeichen zurückzugeben. Um die vorhandenen Antworten nicht ungültig zu machen, können Sie eine Liste einzelner Zeichen (oder Ganzzahlen, die beim Drucken nur 1 Zeichen ergeben) zurückgeben.


Tipps für die lineare Zeit:

  1. Dies kann in 2 parallelen Vorwärtsiterationen oder in einer einzelnen Rückwärtsiteration erfolgen.
  2. Der Status jedes Suffix hängt nur von den ersten beiden Zeichen und dem Typ des zweiten ab.
  3. Durch Scannen des Eingangs in umgekehrter Richtung können Sie L oder S wie folgt bestimmen: $t=$c<=>$d?:$t(PHP 7), wobei $cdas aktuelle Zeichen $dder vorherige und $tder vorherige Typ ist.
  4. Siehe meine PHP-Antwort . Morgen werde ich das Kopfgeld vergeben.

Dies ist meine erste Frage :) Sandbox hat zwei positive Stimmen und keine Kommentare, daher denke ich, dass es bereit ist, veröffentlicht zu werden. Fühlen Sie sich frei, Vorschläge zu machen!
Christoph

Welche Zeichen können in der Eingabe erscheinen?
Martin Ender

@MartinEnder alle Zeichen, die Ihre Zeichenfolge unterstützt, z. B. sogar das Null-Byte für Stilzeichenfolgen c++. Betrachten Sie es als binäre Daten.
Christoph

Was heißt *das
Undichte Nonne

@LeakyNun *bedeutet, dass das entsprechende Suffix vom Typ ist left most s-type. A S-type suffix that is preceeded by a L-type suffix..
Christoph

Antworten:


7

Haskell , 64 53 48 42 Bytes

(0!)
k!(x:y)|x:y>y=1:2!y|2>1=k:0!y
_![]=[]

Probieren Sie es online aus!

Ungolfed, mit Charanstelle von Int:

suffixes :: String -> String
suffixes = go 'S'
 where
   go :: Char -> String -> String
   go _ "" = ""
   go lorstar s | s > tail s = 'L' : go '*' (tail s)
                | otherwise  = lorstar : go 'S' (tail s)

Anonyme Funktionen sind zulässig, daher z=können diese entfernt werden.
Ørjan Johansen

Ich kann Haskell einfach nicht lesen. Würde es Ihnen etwas ausmachen, mir eine kurze Erklärung zu geben?
Christoph

1
@Christoph: Die goFunktion akzeptiert zwei Argumente. Das erste ist das Zeichen, das darstellt, was zur Beschreibung der SSituation verwendet werden soll. Der zweite ist eine Zeichenfolge. Diese Zeichenfolge wird rekursiv durchlaufen, wobei bei jedem Schritt das erste Zeichen entfernt wird (genau das tailtut es). Der Trick ist, dass das erste Argument auf gesetzt wird, *wenn das vorherige Ergebnis a Lwar oder auf Sandere Weise. Auf diese Weise kann in dem Fall, in dem ein *oder ein verwendet Swerden soll, dieses erste Argument direkt verwendet werden. Hoffe das macht Sinn.
Bartavelle

Das ist eine schöne Idee! Ich hoffe, mehr kluge Ideen zu sehen :)
Christoph

@ ØrjanJohansen Wie soll ich das Ergebnis in TIO vorbereiten?
Bartavelle

6

Gelee ,  25 23 21 20  19 Bytes

Ṛ;\UỤỤIṠµI2n×ịØDṚ;0

Ein vollständiges Programm, das die Liste der Zeichen druckt und dabei Folgendes verwendet:

L: 0
S: 8
*: 9

(Als Link wird eine Liste zurückgegeben, in der alle Elemente Zeichen sind, mit Ausnahme des letzten, bei dem es sich um eine Null handelt.)

Probieren Sie es online aus! oder sehen Sie sich die Testsuite an (mit Konvertierung inLS*).

Wie?

Ṛ;\UỤỤIṠµI2n×ịØDṚ;0 - Link: list of characters, s  e.g. "cast"
Ṛ                   - reverse                           "tsac"
  \                 - cumulative reduce by:
 ;                  -   concatenation                   ["t","ts","tsa","tsac"]
   U                - upend (reverse each)              ["t","st","ast","cast"] (suffixes)
    Ụ               - sort indexes by value             [3,4,2,1] (lexicographical order)
     Ụ              - sort indexes by value             [4,3,1,2] (order of that)
      I             - incremental differences           [-1,-2,1] (change)
       Ṡ            - sign                              [-1,-1,1] (comparisons)
        µ           - monadic chain separation, call that x
         I          - incremental differences           [0,2] (only (-1,1) produce 2s)
          2         - literal 2                         2
           n        - not equal?                        [1,0] (indexes of * will be 0)
            ×       - multiply by x (vectorises)        [-1,0,1] (make indexes of *s 0)
              ØD    - decimal yield                     "0123456789"
             ị      - index into (1-indexed & modular)  ['8','9','0']
                Ṛ   - reverse                           ['0','9','8']
                 ;0 - concatenate a zero                ['0','9','8',0]
                    - implicit print                     0980
                    -                              i.e. "L*SL"

Würde es Ihnen etwas ausmachen, eine kleine Erklärung für mich hinzuzufügen?
Christoph

2
Ich werde natürlich tun - ich denke zuerst über mögliche Golfe nach ...
Jonathan Allan


@LeakyNun Wie hast du das herausgefunden?! Sie verwenden dort einen Fehler, von dem ich denke, dass er +auf Strings zu vektorisieren scheint, aber die zugrunde liegenden Ergebnisse sind nicht tatsächlich Jelly-Iterables, sondern Strings (!) (ZB versuchen +@/L€oder +@/L€€oder ...)
Jonathan Allan

@ JonathanAllan Ja, +erzeugt einen tatsächlichen String. Dies ist eine undokumentierte Funktion oder ein Fehler, den Sie als Fehler bezeichnen.
Undichte Nonne


3

JavaScript (ES6), 51 45 Byte

f=(c,d)=>c&&(d<(d=c<(c=c.slice(1))))+d+f(c,d)

6 Bytes dank @Neil gespeichert.

Eine rekursive Lösung für die Übung.

f=(c,d)=>c&&(d<(d=c<(c=c.slice(1))))+d+f(c,d)

console.log(f('mmiissiissiippi')); //LL*SLL*SLL*SLLL   002100210021000
console.log(f('hello world'));     //L*SSL*L*LLL       02110202000
console.log(f('Hello World'));     //SSSSL*SSLLL       11110211000
console.log(f('53Ab§%5qS'));       //L*SSL*SLL         021102100


Speichern Sie 6 Bytes:f=(c,d)=>c&&(d<(d=c<(c=c.slice(1))))+d+f(c,d)
Neil

Danke, @Neil, ich wusste , dass es irgendwo eine Optimierung geben musste.
Rick Hitchcock

2

JavaScript (ES6), 52 Byte

f=
s=>s.replace(/./g,_=>(c<(c=s<(s=s.slice(1))))+c,c=1)
<input oninput=o.textContent=f(this.value)><pre id=o>

Port von @ L3viathans Antwort.


1
@ RickHitchcock Ups, irgendwie habe ich es geschafft, c=1als c=0...
Neil


1

Haskell , 77 75 Bytes, lineare Zeit

f(a:b:c)|let g"L"|a<b="SL";g"S"|a>b="L*";g d=d++d;d:e=f$b:c=g[d]++e
f _="L"

Probieren Sie es online aus!

Wie es funktioniert

Hierbei wird eine Rekursion verwendet, bei der jeweils ein Zeichen vom Anfang der Zeichenfolge entfernt wird. (Der Haskell-Zeichenfolgentyp ist eine einfach verknüpfte Liste von Zeichen, daher ist jeder dieser Schritte zeitkonstant.)

  • Für eine Zeichenfolge abc, bei der a und b einzelne Zeichen sind und c eine beliebige (möglicherweise leere) Zeichenfolge ist,
    • f ( abc ) = SL e , wenn f ( bc ) = L e und a < b ;
    • f ( abc ) = L * e , wenn f ( bc ) = S e und a > b ;
    • f ( abc ) = LL e , wenn f ( bc ) = L e und ab ;
    • f ( abc ) = SSe , wenn f ( bc ) = Se und ab .
  • Für eine Einzelzeichenfolge a ist f ( a ) = L.

1
Könnten Sie bitte eine Erklärung geben?
R. Kap

Bitte geben Sie eine Beschreibung an, damit ich überprüfen kann, ob dies in linearer Zeit abläuft.
Christoph

@Christoph Hinzugefügt.
Anders Kaseorg

@AndersKaseorg danke fürs Hinzufügen! Leider scheint dies im Vergleich zu der anderen Haskell-Antwort ziemlich ausführlich zu sein. Könnte dies weiter golfen, wenn man es nicht benutzt S, L and *?
Christoph

1
@Christoph Um klar zu sein, [1,1,2,0,1,1,2,0,1,1,2,0,1,1,1]ist eine Liste von einstelligen Zahlen, keine Liste von einzelnen Zeichen. In meinem Fall denke ich, dass die Ausgabe einer Liste von Zahlen mir keine Bytes ersparen würde.
Anders Kaseorg

1

Python 2 , 65 55 Bytes

Rekursive Version, basierend auf L3viathan Antwort , mit 012wie LS*:

def g(s,d=2):c=s<s[1:];return s and`c+(d<c)`+g(s[1:],c)

Probieren Sie es online aus!

Python 3 , 65 59 Bytes

Rekursive Lösung mit L, Sund *:

f=lambda s:s and('LS'[s<s[1:]]+f(s[1:])).replace('LS','L*')

Läuft von vorne durch die Zeichenfolge und ersetzt alle Instanzen von LSdurchL*

Probieren Sie es online aus!


1
blah if s else''s and blahspart sechs Bytes. In Python 2 speichert str(blah)`blah`weitere drei Bytes für die zweite Lösung.
Anders Kaseorg

1

PHP, 82 Byte, lineare Zeit

for($a=$argn;a&$c=$a[$i-=1];$d=$c)$a[$i]=2+$t=$d<=>$c?:$t;echo strtr($a,[13=>12]);

Überläuft die Eingabe von rechts nach links und ersetzt jedes Zeichen durch den Typ.

$t=$d<=>$c?:$t

Berechnet den Typ anhand des aktuellen und des vorherigen Zeichens (-1 oder 1). Wenn gleich, ändert sich der Typ nicht.


+1 für die Idee mitstrtr
Jörg Hülsermann

1

PHP , 70 Bytes

L = 1, S = 0, * = 2

Für den letzten Testfall mit den §+3 Bytes wird mb_substrstattdessen Multibyte-Unterstützung benötigtsubstr

for(;$s=&$argn;$s=$u)$r.=$l=($l&1)+(1&$l^($s>$u=substr($s,1)));echo$r;

Probieren Sie es online aus!

PHP , 71 Bytes

L = 1, S = 0, * = 2

for(;$s=&$argn;$s=$u)$r.=+($s>$u=substr($s,1));echo strtr($r,[10=>12]);

Probieren Sie es online aus!

PHP , 74 Bytes

for(;$s=&$argn;$s=$u)$r.=SL[$s>$u=substr($s,1)];echo strtr($r,[LS=>"L*"]);

Probieren Sie es online aus!


$s=&$argnziemlich schlau ! Ich bin mir ziemlich sicher, dass es eine bessere Antwort gibt;) Hoffentlich kommt jemand darauf :)
Christoph

@Christoph Ich habe das Gefühl, dass mir etwas fehlt. Ich habe versucht, das letzte LS * in einem Varibale zu speichern, aber es ist länger
Jörg Hülsermann

@Christoph meinst du so? Ich konnte nicht wirklich sehen, warum der letzte Testfall falsch ist. Probieren Sie es online aus!
Jörg Hülsermann

@Christoph Okay, ich habe gesehen, warum es für den letzten Testfall, den ich verwenden muss, nicht funktioniert, mb_substranstatt substrwenn die Eingabe nicht im einfachen ASCII-Bereich liegt. Muss der letzte Testfall unterstützt werden?
Jörg Hülsermann

1
@Christoph Danke In diesem Fall ignoriere ich den letzten Testfall mit dem§
Jörg Hülsermann
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.