Loại hậu tố của tôi là gì?


10

Giới thiệu

Vì vậy, tôi đã lãng phí thời gian của mình một lần nữa để nghiên cứu các thuật toán sắp xếp hậu tố, đánh giá các ý tưởng mới bằng tay và bằng mã. Nhưng tôi luôn đấu tranh để nhớ các loại hậu tố của tôi! Bạn có thể cho tôi biết loại hậu tố của tôi là gì?

Còn lại - gì nhất?

Rất nhiều thuật toán sắp xếp hậu tố (SAIS, KA, dwar riêng của tôi) nhóm hậu tố thành các loại khác nhau để sắp xếp chúng. Có hai loại cơ bản: S-typeL-type hậu tố. Hậu tố loại S là hậu tố ít hơn về mặt từ vựng ( S maller) so với hậu tố và loại L sau nếu nó lớn hơn về mặt từ vựng ( L arger). Một loại S hầu hết bên trái ( loại LMS ) chỉ là: Hậu tố loại S được đặt trước bởi hậu tố loại L.

Điều đặc biệt về các hậu tố kiểu LMS này là một khi chúng ta sắp xếp chúng, chúng ta có thể sắp xếp tất cả các hậu tố khác theo thời gian tuyến tính! Điều đó thật tuyệt phải không?

Các thách thức

Cho một chuỗi giả sử nó bị chấm dứt bởi một ký tự đặc biệt nhỏ hơn bất kỳ ký tự nào khác trong chuỗi đó (ví dụ nhỏ hơn cả byte rỗng). Xuất ra một kiểu corrosponding char cho mỗi hậu tố.

Bạn có thể tự do chọn char để sử dụng cho loại nhưng tôi muốn L, S and *cho L-, S- and LMS-typemiễn là họ đều có thể in được ( 0x20 - 0x7E).

Thí dụ

Cho mmiissiissiippiđầu ra chuỗi (khi sử dụng L, S and *):

 LL*SLL*SLL*SLLL

Ví dụ, điều đầu tiên Llà do thực tế mmiissiissiippi$là lớn hơn về mặt từ vựng miissiissiippi$( $đại diện cho ký tự tối thiểu được thêm vào):

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

Một số ví dụ khác:

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

Mục tiêu

Tôi không ở đây để làm phiền Peter Cordes (đôi khi tôi sẽ làm điều này trên stackoverflow); Tôi chỉ rất lười biếng nên đây dĩ nhiên ! Câu trả lời ngắn nhất trong byte thắng.


Chỉnh sửa: Thứ tự các ký tự được cho bởi giá trị byte của chúng. Đó là phương tiện so sánh nên giống như C strcmp.

Chỉnh sửa2: Giống như đã nêu trong đầu ra nhận xét phải là một ký tự cho mỗi ký tự đầu vào. Mặc dù tôi cho rằng sẽ được hiểu là "trả về một chuỗi" nhưng có vẻ như ít nhất 1 câu trả lời trả về một danh sách các ký tự đơn. Để không làm mất hiệu lực các câu trả lời hiện có, tôi sẽ cho phép bạn trả về một danh sách các ký tự đơn (hoặc số nguyên mà khi in kết quả chỉ trong 1 char).


Lời khuyên cho thời gian tuyến tính:

  1. Nó có thể được thực hiện trong 2 lần lặp tiến song song hoặc trong một lần lặp ngược duy nhất.
  2. Trạng thái của mỗi hậu tố chỉ phụ thuộc vào 2 ký tự đầu tiên và loại thứ hai.
  3. Quét đầu vào theo hướng ngược lại, bạn có thể xác định L hoặc S như thế này: $t=$c<=>$d?:$t(PHP 7), trong đó $cchar hiện tại $dlà loại trước và $tloại trước.
  4. Xem câu trả lời PHP của tôi . Ngày mai tôi sẽ trao tiền thưởng.

Đây là câu hỏi đầu tiên của tôi :) Sandbox có hai lượt upvote và không có bình luận nào nên tôi nghĩ nó đã sẵn sàng để đăng. Hãy góp ý!
Christoph

Những ký tự nào có thể xuất hiện trong đầu vào?
Martin Ender

@MartinEnder tất cả các ký tự chuỗi của bạn hỗ trợ, ví dụ như byte rỗng cho c++chuỗi kiểu. Hãy nghĩ về nó như là dữ liệu nhị phân.
Christoph

*nghĩa là gì?
Rò rỉ Nun

@LeakyNun *có nghĩa là hậu tố tương ứng là loại left most s-type. A S-type suffix that is preceeded by a L-type suffix..
Christoph

Câu trả lời:


7

Haskell , 64 53 48 42 byte

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

Hãy thử trực tuyến!

Ungolfed, với Charthay vì 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)

Các chức năng ẩn danh được cho phép, vì vậy z=có thể được gỡ bỏ.
Ørjan Johansen

Tôi không thể đọc Haskell. Bạn có phiền cho tôi một lời giải thích ngắn gọn?
Christoph

1
@Christoph: gohàm có hai đối số. Đầu tiên là nhân vật đại diện cho những gì nên được sử dụng để mô tả Stình huống. Thứ hai là một chuỗi. Nó đi qua chuỗi đó một cách đệ quy, loại bỏ ký tự đầu tiên ở mỗi bước (đó là những gì tail). Thủ thuật là đối số đầu tiên được đặt thành *khi kết quả trước đó là a L, hoặc Snếu không. Theo cách đó, trong trường hợp nên sử dụng một *hoặc một S, đối số đầu tiên có thể được sử dụng trực tiếp. Hy vọng rằng có ý nghĩa.
bartavelle

Đó là một ý tưởng hay! Tôi hy vọng sẽ thấy nhiều ý tưởng thông minh hơn :)
Christoph

@ RjanJohansen Tôi phải chuẩn bị kết quả như thế nào trong TIO?
bartavelle

6

Thạch ,  25 23 21 20  19 byte

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

Một chương trình đầy đủ in danh sách các ký tự, sử dụng:

L: 0
S: 8
*: 9

(Là một liên kết, nó trả về một danh sách trong đó tất cả các mục là ký tự ngoại trừ mục cuối cùng là số không.)

Hãy thử trực tuyến! hoặc xem bộ thử nghiệm (có chuyển đổi thànhLS*).

Làm sao?

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

Bạn có phiền thêm một lời giải thích nhỏ cho tôi không?
Christoph

2
Tất nhiên tôi sẽ làm - tôi đang nghĩ về những môn golf có thể có trước ...
Jonathan Allan


@LeakyNun Bạn đã làm việc đó như thế nào?! Bạn đang sử dụng một lỗi ở đó tôi nghĩ rằng các +chuỗi dường như vectơ nhưng kết quả cơ bản không thực sự là Jelly iterables mà là các chuỗi (!) (Ví dụ: thử +@/L€hoặc +@/L€€hoặc ...)
Jonathan Allan

@Jonathan ALLan có, +tạo chuỗi thực tế. Đây là một tính năng không có giấy tờ, hoặc những gì bạn gọi là lỗi.
Rò rỉ Nun

3

Python 3, 92 87 74 69 65 byte

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

Sử dụng 0cho L, 1cho S2cho *. Bọc chuỗi đầu vào trong ký tự trích dẫn; Tôi tin rằng điều này được cho phép bởi quy ước.

Hãy thử trực tuyến!

Ví dụ sử dụng:

mmiissiissiippi
002100210021000

đã lưu 5 byte nhờ Leaky Nun, 4 byte nhờ vào ovs




3

JavaScript (ES6), 51 45 byte

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

Đã lưu 6 byte nhờ @Neil.

Một giải pháp đệ quy cho bài tập.

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


Lưu 6 byte:f=(c,d)=>c&&(d<(d=c<(c=c.slice(1))))+d+f(c,d)
Neil

Cảm ơn, @Neil, tôi biết rằng phải có một sự tối ưu hóa ở đó ở đâu đó.
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>

Câu trả lời của cảng @ L3viathan.


1
@RickHitchcock Rất tiếc, bằng cách nào đó tôi đã quản lý để chuyển c=1thành c=0...
Neil


1

Haskell , 77 75 byte, thời gian tuyến tính

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"

Hãy thử trực tuyến!

Làm thế nào nó hoạt động

Điều này sử dụng đệ quy, tước bỏ một ký tự tại một thời điểm từ đầu chuỗi. (Loại chuỗi Haskell là danh sách các ký tự được liên kết đơn, vì vậy mỗi bước này là thời gian không đổi.)

  • Đối với một chuỗi abc trong đó ab là các ký tự đơn và c là bất kỳ chuỗi nào (có thể trống),
    • f ( abc ) = SL e , nếu f ( bc ) = L ea < b ;
    • f ( abc ) = L * e , nếu f ( bc ) = S ea > b ;
    • f ( abc ) = LL e , nếu f ( bc ) = L eab ;
    • f ( abc ) = SS e , nếu f ( bc ) = S eab .
  • Đối với chuỗi ký tự đơn a , f ( a ) = L

1
Bạn có thể vui lòng cung cấp một lời giải thích?
R. Kap

Vui lòng cung cấp một mô tả để tôi có thể xác nhận rằng điều này chạy trong thời gian tuyến tính.
Christoph

@Christoph Đã thêm.
Anders Kaseorg

@AndersKaseorg cảm ơn vì đã thêm! Đáng buồn thay, điều này có vẻ khá dài dòng so với câu trả lời Haskell khác. Điều này có thể được đánh golf hơn nữa bằng cách không sử dụng S, L and *?
Christoph

1
@Christoph Để rõ ràng, [1,1,2,0,1,1,2,0,1,1,2,0,1,1,1]là một danh sách các số có một chữ số, không phải là danh sách các ký tự đơn. Trong trường hợp của tôi, tôi nghĩ rằng việc đưa ra một danh sách các số sẽ không tiết kiệm cho tôi bất kỳ byte nào.
Anders Kaseorg

1

Python 2 , 65 55 byte

Phiên bản đệ quy, dựa trên câu trả lời của L3viathan , sử dụng 012như LS*:

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

Hãy thử trực tuyến!

Python 3 , 65 59 byte

Giải pháp đệ quy sử dụng L, S*:

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

Chạy qua chuỗi từ phía trước và thay thế tất cả các trường hợp LSbằngL*

Hãy thử trực tuyến!


1
blah if s else''s and blahlưu sáu byte. Trong Python 2, str(blah)`blah`lưu ba byte khác vào giải pháp thứ hai.
Anders Kaseorg

1

PHP, 82 byte, thời gian tuyến tính

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

Đi qua đầu vào từ phải sang trái và thay thế từng char bằng loại.

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

Tính toán cho loại hiện tại và char trước (-1 hoặc 1). Nếu bằng nhau loại không thay đổi.


+1 cho ý tưởng vớistrtr
Jörg Hülsermann

1

PHP , 70 byte

L = 1, S = 0, * = 2

Thay vào đó, cần có Hỗ trợ đa lõi cho Testcase cuối cùng với §+3 Bytemb_substrsubstr

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

Hãy thử trực tuyến!

PHP , 71 byte

L = 1, S = 0, * = 2

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

Hãy thử trực tuyến!

PHP , 74 byte

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

Hãy thử trực tuyến!


$s=&$argnkhá thông minh ! Tôi khá chắc chắn rằng có một câu trả lời tốt hơn mặc dù;) Hy vọng ai đó nghĩ ra nó :)
Christoph

@Christoph Tôi có cảm giác là tôi đang bỏ lỡ điều gì đó. Tôi đã cố gắng lưu trữ LS * cuối cùng trong một varibale nhưng nó dài hơn
Jörg Hülsermann

@Christoph có nghĩa là bạn thích như vậy? Tôi không thực sự thấy lý do tại sao các thử nghiệm
Jörg Hülsermann

@Christoph Được rồi tôi đã thấy nó tại sao nó không hoạt động cho testcase cuối cùng tôi phải sử dụng mb_substrthay vì substrnếu đầu vào không nằm trong phạm vi ascii đơn giản. Có cần thiết để hỗ trợ các testcase cuối cùng?
Jörg Hülsermann

1
@Christoph Cảm ơn bạn Trong trường hợp này, tôi bỏ qua bài kiểm tra cuối cùng với§
Jörg Hülsermann
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.