접미사는 어떤 유형입니까?


10

소개

그래서 나는 접미사 정렬 알고리즘을 연구하면서 새로운 시간을 수작업으로 코드로 평가하면서 다시 시간을 낭비했습니다. 그러나 나는 항상 내 접미사의 유형을 기억하려고 노력합니다! 내 접미사가 어떤 유형인지 알려줄 수 있습니까?

가장 왼쪽?

많은 접미사 정렬 알고리즘 (SAIS, KA, 내 자신의 daware) 그룹 접미사를 정렬하기 위해 다른 유형으로 접미사를 그룹화합니다. 기본 유형에는 S 유형L 유형 접미사가 있습니다. S- 타입 접미어는 다음 접미어보다 사전 어휘 적으로 작은 ( S maller) 접미어이고 L 이 큰 경우 ( L arger) L- 타입입니다. A는 가장 왼쪽 S 형 ( LMS-타입 )이며 단지하십시오 S 형 a로 덧붙일 접미사 L 형 접미사.

LMS 유형 접미사 에 대한 특별한 점은 일단 정렬하면 다른 모든 접미사를 선형 시간으로 정렬 할 수 있다는 것입니다! 굉장하지 않습니까?

도전

주어진 문자열은 해당 문자열의 다른 문자보다 작은 특수 문자 (예 : 널 바이트보다 작은 문자)로 종료한다고 가정합니다. 각 접미사에 대해 유형 부식 문자를 출력하십시오.

어떤 유형에 어떤 문자를 사용할 것인지 자유롭게 선택할 수 있지만 모두 인쇄 할 수있는 한 선호 L, S and *합니다 L-, S- and LMS-type( 0x20 - 0x7E).

주어진 문자열 mmiissiissiippi출력 (을 사용할 때 L, S and *) :

 LL*SLL*SLL*SLLL

예를 들어 첫 번째 Lmmiissiissiippi$사전 식보다 큰 사실 때문입니다 miissiissiippi$( $추가 된 최소 문자를 나타냄).

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$               > $

몇 가지 예 :

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

나는 Peter Cordes를 성가 시게 여기에 있지 않습니다 (언제나 스택 오버 플로우 에서이 작업을 수행 할 것입니다). 나는 매우 게으르다. 그래서 이것은 물론 ! 바이트 단위의 최단 답변이 이깁니다.


편집 : 문자의 순서는 바이트 값으로 제공됩니다. 즉, 비교는 C와 같아야합니다 strcmp.

Edit2 : 주석 출력에서 ​​언급 된 것처럼 각 입력 문자에 대해 단일 문자 여야합니다. "문자열 반환"으로 이해한다고 가정했지만 적어도 하나의 답변이 단일 문자 목록을 반환하는 것으로 보입니다. 기존 답변을 무효화하지 않기 위해 단일 문자 목록 (또는 인쇄 할 때 1 문자 만 정수)을 반환 할 수 있습니다.


선형 시간에 대한 팁 :

  1. 2 병렬 순방향 반복 또는 단일 역방향 반복으로 수행 할 수 있습니다.
  2. 각 접미사 상태는 처음 두 문자와 두 번째 문자에만 의존합니다.
  3. 입력을 역방향으로 스캔하면 L 또는 S를 다음과 같이 결정할 수 있습니다. $t=$c<=>$d?:$t(PHP 7), $c현재 문자 $d는 이전 문자 및 $t이전 유형입니다.
  4. PHP 답변을 참조하십시오 . 내일 나는 현상금을 수여 할 것이다.

이것은 내 첫 번째 질문입니다 :) 샌드 박스 에는 의견이 두 개 있으며 의견이 없으므로 게시 할 준비가 된 것 같습니다. 제안을 주시기 바랍니다!
Christoph

입력에 어떤 문자가 나타날 수 있습니까?
Martin Ender 2016 년

@MartinEnder 문자열에서 문자열을 지원하는 모든 문자 (예 : c++스타일 문자열의 경우 null 바이트) 이진 데이터로 생각하십시오.
Christoph

무슨 *뜻입니까?
Leaky Nun

@LeakyNun *은 해당 접미사가 유형 임을 의미합니다 left most s-type. A S-type suffix that is preceeded by a L-type suffix..
Christoph

답변:


7

하스켈 , 64 53 48 42 바이트

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

온라인으로 사용해보십시오!

ungolfed, Char대신 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)

익명 기능이 허용되므로이 기능을 z=제거 할 수 있습니다.
Ørjan Johansen 2016

나는 단지 Haskell을 읽을 수 없습니다. 간단한 설명을 해주시겠습니까?
Christoph

1
@Christoph :이 go함수는 두 가지 인수를 취합니다. 첫 번째는 S상황 을 설명하는 데 사용해야하는 것을 나타내는 문자입니다 . 두 번째는 문자열입니다. 각 단계에서 첫 번째 문자를 제거하여 해당 문자열을 재귀 적으로 통과합니다 (그것이하는 일입니다 tail). 트릭은 첫 번째 인수가 *이전 결과가 L또는 S기타 일 때 설정되는 것 입니다. 이렇게하면 경우 *또는이 S사용되어야하며, 그 첫 번째 인수는 직접 사용될 수있다. 이해가 되길 바랍니다.
bartavelle 2016 년

아주 좋은 생각입니다! 나는 더 영리한 아이디어를 기대하고있다 :)
Christoph

@ ØrjanJohansen 어떻게 TIO에서 결과를 준비해야합니까?
bartavelle 2016 년

6

젤리 ,  25 23 21 20  19 바이트

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

다음을 사용하여 문자 목록을 인쇄하는 전체 프로그램 :

L: 0
S: 8
*: 9

(링크로서 마지막 항목을 제외한 모든 항목이 0 인 목록을 반환합니다.)

온라인으로 사용해보십시오! 또는 테스트 스위트를 참조하십시오(로 변환LS*).

어떻게?

Ṛ;\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"

저에게 작은 설명을 추가해 주시겠습니까?
Christoph

2
물론 할 것입니다-가능한 골프에 대해 먼저 생각하고 있습니다.
Jonathan Allan


@LeakyNun 어떻게 해결 했습니까?! +문자열에서 벡터화하는 것으로 생각되는 버그를 사용하고 있지만 기본 결과는 실제로 Jelly iterables가 아니라 문자열 (!)입니다 (예 : try +@/L€또는 +@/L€€or ...)
Jonathan Allan

@JonathanAllan 예, +실제 문자열을 생성합니다. 이것은 문서화되지 않은 기능이거나 버그라고 부릅니다.
Leaky Nun

3

파이썬 3, 92 87 74 69 65 바이트

s=input()
c=1
while s:d=s<s[1:];print(d+(c<d),end='');s=s[1:];c=d

사용 0을 위해 L, 1대한 S, 및 2위해 *. 입력 문자열을 따옴표로 묶으십시오. 나는 이것이 관습에 의해 허용된다고 생각합니다.

온라인으로 사용해보십시오!

사용 예 :

mmiissiissiippi
002100210021000

Leaky Nun 덕분에 5 바이트 절약, ovs 덕분에 4 바이트 절약




3

자바 스크립트 (ES6), 51 45 바이트

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

@Neil 덕분에 6 바이트를 절약했습니다.

운동에 대한 재귀 솔루션.

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


6 바이트 저장 :f=(c,d)=>c&&(d<(d=c<(c=c.slice(1))))+d+f(c,d)
Neil

감사합니다, @Neil, 저는 어딘가에 최적화가 있어야 한다는 것을 알고 있었습니다.
Rick Hitchcock

2

자바 스크립트 (ES6), 52 바이트

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>

@ L3viathan의 답변 포트.


1
@RickHitchcock 죄송합니다, 어떻게 든 내가 포트 c=1로 관리 했습니다 c=0...
Neil


1

Haskell , 77 75 바이트, 선형 시간

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"

온라인으로 사용해보십시오!

작동 원리

이것은 문자열의 시작 부분에서 한 번에 한 문자 씩 제거하여 재귀를 사용합니다. Haskell 문자열 유형은 단일 링크 문자 목록이므로 이러한 각 단계는 상수 시간입니다.

  • ab 가 단일 문자이고 c 가 임의의 빈 문자열 인 문자열 abc의 경우 ,
    • F ( ABC )의 SL = E , 만일 F ( BC ) = L E 및 < B ;
    • F ( ABC ) = L * , 만일 F ( BC ) = S E 및 > B ;
    • F ( ABC ) = LL의 E , 만일 F ( BC ) = L의 E 및 ≥ B ;
    • F ( ABC ) = SS , 만일 F ( BC ) = S의 E 및 ≤의 B .
  • 단일 문자 문자열 a의 경우 f ( a ) = L입니다.

1
설명을 제공해 주시겠습니까?
R. Kap

선형 시간으로 실행되는지 확인할 수 있도록 설명을 입력하십시오.
Christoph

@Christoph가 추가되었습니다.
Anders Kaseorg

@AndersKaseorg를 추가해 주셔서 감사합니다! 슬프게도 이것은 다른 Haskell 답변과 비교하여 상당히 장황한 것처럼 보입니다. 이것을 사용하지 않으면 서 더 골프를 칠 수 S, L and *있습니까?
Christoph

1
@Christoph 분명히 말하면, [1,1,2,0,1,1,2,0,1,1,2,0,1,1,1]단일 문자 목록이 아닌 한 자리 숫자의 목록입니다. 필자의 경우 숫자 목록을 출력해도 바이트가 절약되지 않는다고 생각합니다.
Anders Kaseorg

1

파이썬 2 , 65 55 바이트

를 기반으로 재귀 버전, L3viathan의 대답 사용 012으로 LS*:

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

온라인으로 사용해보십시오!

파이썬 3 , 65 59 바이트

재귀 솔루션을 사용하여 L, S*:

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

앞에서 문자열을 통해 실행하고의 모든 인스턴스 LSL*

온라인으로 사용해보십시오!


1
blah if s else''s and blah6 바이트를 저장합니다. Python 2에서는 str(blah)`blah`두 번째 솔루션에 3 바이트를 더 저장합니다.
Anders Kaseorg

1

PHP, 82 바이트, 선형 시간

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

입력을 오른쪽에서 왼쪽으로 이동하고 각 문자를 유형으로 바꿉니다.

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

현재와 ​​이전 문자가 주어진 유형을 계산합니다 (-1 또는 1). 같으면 유형이 변경되지 않습니다.


와 아이디어에 대한 한strtr
요 르그 Hülsermann

1

PHP , 70 바이트

L = 1, S = 0, * = 2

§+3 바이트 mb_substr대신 마지막 테스트 케이스에 멀티 바이트 지원이 필요합니다.substr

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

온라인으로 사용해보십시오!

PHP , 71 바이트

L = 1, S = 0, * = 2

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

온라인으로 사용해보십시오!

PHP , 74 바이트

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

온라인으로 사용해보십시오!


$s=&$argn꽤 영리한! 그래도 더 나은 대답이 있다고 확신합니다.)) 누군가가 그것을 생각해 냈습니다 :)
Christoph

@Christoph 나는 뭔가를 놓친 느낌이 있습니다. 나는 마지막 LS가 varibale에 * 저장하려고해야하지만 이상
요 르그 Hülsermann

@Christoph는 당신이 그렇게 좋아한다는 것을 의미합니까? 마지막 테스트 케이스가 왜 틀린지 실제로 알지 못했습니다 . 온라인으로 사용해보십시오!
Jörg Hülsermann 2016 년

그렇지 내가 사용해야합니다 마지막 테스트 케이스 작동 왜 그것을 본 @Christoph 좋아 mb_substr대신 substr입력이 간단한 ASCII 범위에없는 경우. 마지막 테스트 케이스를 지원해야합니까?
Jörg Hülsermann 2016 년

1
@Christoph 내가 가진 마지막 테스트 케이스 무시이 경우 감사합니다§
요 르그 Hülsermann
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.