class NgLib:: RollingHash

Overview

文字列 $S$ に対して、上手なハッシュを作ることで、比較やLCPを高速に求めます。

Defined in:

nglib/string/rolling_hash.cr

Constant Summary

MOD = ( 1_u64 << 61 ) - 1

Constructors

Class Method Summary

Instance Method Summary

Constructor Detail

def self. new (a : Array( Int ), base : UInt64 | Nil = nil ) #

配列 $a$ に対する、基数が base のロリハを構築します。

base は指定しない場合、ランダムに生成されます。

rh = RollingHash.new([1, 2, 5, 1, 2])

[ View source ]
def self. new (s : String, base : UInt64 | Nil = nil ) #

文字列 $s$ に対する、基数が base のロリハを構築します。

base は指定しない場合、ランダムに生成されます。

rh = RollingHash.new("missisippi")

[ View source ]
def self. new (size : Int32, a : Enumerable, base : UInt64 | Nil = nil ) #

Enumerable な列 $a$ に対する、基数が base のロリハを構築します。

base は指定しない場合、ランダムに生成されます。

rh = RollingHash.new(5, [1, 2, 5, 1, 2])

[ View source ]

Class Method Detail

def self. create_base #

ランダムに基底を生成します。

base = RollingHash.create_base
base # => 1729

[ View source ]
def self. lcp (rh1 : self , rh2 : self , i : Int = 0 , j : Int = 0 ) : Int32 #

s[i...] t[j...] の最長共通接頭辞の長さを返します。

$i, j$ はデフォルトで $0$ を渡しています。

rh1 = RollingHash.new("missisippi", base: 628)
rh2 = RollingHash.new("thisisapen", base: 628)
RollingHash.lcp(rh1, rh2)       # => 0
RollingHash.lcp(rh1, rh2, 4, 2) # => 3

[ View source ]

Instance Method Detail

def [] (range : Range( Int | Nil, Int | Nil)) : UInt64 #

range で指定した範囲 s[range] のハッシュを返します。

rh = RollingHash.new("missisippi")
rh[4..5] # => 339225237399054811
rh[5..6] # => 339225237399054811

[ View source ]
def concat (h1 : UInt64, h2 : UInt64, h2_len : Int ) : UInt64 #

ハッシュ値 $h_1$ とハッシュ値 $h_2$ を結合したときのハッシュ値を返します。

ハッシュ値 $h_2$ の元々の長さを渡す必要があります。

rh = RollingHash.new("missisippi")
h1 = rh[1..2] # "is"
h2 = rh[5..6] # "si"
h = rh.concat(h1, h2, h2_len: 2)
h == rh.[1..4] # => true

[ View source ]
def hash (s : String) #

文字列 $s$ のハッシュを返します。

rh = RollingHash.new("missisippi")
rh.hash("is")  # => 339225237399054811
rh.hash("abc") # => 496222201481864933

[ View source ]
def hash (s : Enumerable) #

列 $s$ のハッシュを返します。

rh = RollingHash.new("missisippi")
rh.hash("is")  # => 339225237399054811
rh.hash("abc") # => 496222201481864933

[ View source ]
def hash : UInt64 #

初期化時に使用した列に対するハッシュを返します。

rh = RollingHash.new("missisippi")
rh.hash               # => 339225237399054811
rh.hash("missisippi") # => 339225237399054811

[ View source ]
def index (t : String, offset : Int = 0 ) : Int32 | Nil #

文字列検索を行います。

s[offset..] から t と一致する初めての添字を返します。 添字は s が基準です。また、 offset が加算された値が返ります。

存在しない場合は nil を返します。

rh = RollingHash.new("missisippi", base: 628)
rh.index("is")            # => 1
rh.index("is", offset: 4) # => 4
rh.index("mid")           # => nil
rh.index("i")             # => 1
rh.index("pi")            # => 8

[ View source ]
def index (t : Enumerable, offset : Int = 0 ) : Int32 | Nil #

検索を行います。

s[offset..] から t と一致する初めての添字を返します。 添字は s が基準です。また、 offset が加算された値が返ります。

存在しない場合は nil を返します。

rh = RollingHash.new("missisippi", base: 628)
rh.index("is")            # => 1
rh.index("is", offset: 4) # => 4
rh.index("mid")           # => nil
rh.index("i")             # => 1
rh.index("pi")            # => 8

[ View source ]
def index! (t : String, offset : Int = 0 ) : Int32 #

文字列検索を行います。

s[offset..] から t と一致する初めての添字を返します。 添字は s が基準です。また、 offset が加算された値が返ります。

存在しない場合は例外を投げます。

rh = RollingHash.new("missisippi", base: 628)
rh.index!("is")            # => 1
rh.index!("is", offset: 4) # => 4
rh.index!("mid")           # => Enumerable::NotFoundError
rh.index!("i")             # => 1
rh.index!("pi")            # => 8

[ View source ]
def index! (t : Enumerable, offset : Int = 0 ) : Int32 #

検索を行います。

s[offset..] から t と一致する初めての添字を返します。 添字は s が基準です。また、 offset が加算された値が返ります。

存在しない場合は例外を投げます。

rh = RollingHash.new("missisippi", base: 628)
rh.index!("is")            # => 1
rh.index!("is", offset: 4) # => 4
rh.index!("mid")           # => Enumerable::NotFoundError
rh.index!("i")             # => 1
rh.index!("pi")            # => 8

[ View source ]
def lcp (i : Int , j : Int , other = self ) : Int32 #

s[i...] other[j...] の最長共通接頭辞の長さを返します。

other はデフォルトで自分自身を渡しています。 自分自身以外を渡す場合は $(mod, base)$ が一致している必要があります。

rh1 = RollingHash.new("missisippi")
rh1 = rh1.lcp(3, 5) # => 2
rh1 = rh1.lcp(0, 1) # => 0

[ View source ]
def size : Int32 #

[ View source ]
def slice (range : Range( Int | Nil, Int | Nil)) : UInt64 #

range で指定した範囲 s[range] のハッシュを返します。

rh = RollingHash.new("missisippi")
rh.slice(4..5) # => 339225237399054811
rh.slice(5..6) # => 339225237399054811

[ View source ]
def substr (start : Int , length : Int ) : UInt64 #

s[start...start + length] のハッシュを返します。

rh = RollingHash.new("missisippi")
rh.substr(4, length: 2) # => 339225237399054811
rh.substr(5, length: 2) # => 339225237399054811

[ View source ]