15 章「真珠の列」 - 珠玉のプログラミング(Programming Pearls)

珠玉のプログラミングの15章。

15.5.1

タグを無視すればよい。レイアウト情報の削除をする。

15.5.2

全ての単語を set/map に保持する。その分だけメモリが必要。

15.5.3

incword の中は探索に時間がかかっているのでそこまで速くならない。

15.5.4

略。

15.5.5

map をソート。

15.5.6

サフィックス配列を2分探索して近い物を見つける。

15.5.7

全て同じ文字だと比較に多くの時間が割かれるので遅くなる。実際に計測したが 10 倍以上遅くなった。

15.5.8

max = M としてスタートすればよい。

15.5.9

suffix array に付属データとしてどちらの配列のデータかのフラグを持たせる。

15.5.10

最後の出力の時に前後の文字を見て最長を決める。

15.5.11-15

マルコフ連鎖は以前、書いた事があるので略。

15.5.16

適当な文章を見つけてきて suffix array を作り重複している単語をリストに入れる。

15.5.17

BlockSorting を利用した圧縮に使われているらしい。

コード

;; Programming Pearls Chapter 15
;; Programming Pearls Chapter 15
(import (rnrs)
        (mosh)
        (mosh file)
        (mosh control)
        (only (srfi :13) string<= string-prefix-length)
        (mosh test))

(define (make-suffix-array str)
  (let1 vec (make-vector (string-length str))
    (do ([i 0 (+ i 1)])
        ((= i (vector-length vec)))
      (vector-set! vec i i))
    (let1 len (string-length str)
      (vector-sort! (lambda (i j)
                      (string<= str str i len j len))
                    vec))
    vec))

(define (find-longest-shared str sa)
  (let loop ([i 0]
             [max-index 0]
             [max-len 0])
    (cond
     [(= (- (vector-length sa) 1) i)
      (substring str max-index (+ max-index max-len))]
     [else
      (let* ([len (string-length str)]
             [common-len (string-prefix-length str str (vector-ref sa i) len (vector-ref sa (+ i 1)) len)])
        (if (> common-len max-len)
            (loop (+ i 1) (vector-ref sa i) common-len)
            (loop (+ i 1) max-index max-len)))])))

(define (main args)
  (let1 content (file->string (cadr args))
    (write (find-longest-shared content (make-suffix-array content)))))

(main (command-line))