* I really don't know Ruby *
#encoding: utf-8
# ====================================================== =============================
# ■ Suffix_Automaton
# ------------------------------------------------- -----------------------------
# Suffix automaton.
# ====================================================== ===============================
class Suffix_Automaton
# ------------------------------------------------- -------------------------
# ● Define instance variables
# ------------------------------------------------- -------------------------
attr_reader: total # number of different substrings in current SAM
attr_reader: root # root node of SAM
# ====================================================== =============================
# ■ State
# ------------------------------------------------- -----------------------------
# Suffix automata status node.
# ================================================= =============================
class State
# ------------------------------------------------- -------------------------
# ● Define instance variables
# ------------------------------------------------- -------------------------
attr_accessor: par # parent
attr_accessor: go # go
attr_accessor: val # val
# ------------------------------------------------- -------------------------
# ● Initialization status node
# ------------------------------------------------- -------------------------
def init (val = 0)
@par = nil
@go = []
@val = val
for i in 0..26 do
@go [i] = nil
end
end
# ------------------------------------------------- -------------------------
# ● Calculate the number of different substrings represented by the node
# ------------------------------------------------- -------------------------
def calc
return 0 if @par == nil
return @val-@ par.val
end
end
# ------------------------------------------------- -------------------------
# ● Initialize the suffix automaton
# ------------------------------------------------- -------------------------
def initSAM
@total = 0
@cur = 0
@nodePool = []
@root = newState
@last = @root
end
# ------------------------------------------------- -------------------------
# ● Create a new status node
# ------------------------------------------------- -------------------------
def newState (val = 0)
@nodePool [@cur] = State.new
@nodePool [@cur] .init (val)
@cur + = 1
return @nodePool [@ cur-1]
end
# ------------------------------------------------- -------------------------
# ● Add characters
# ------------------------------------------------- -------------------------
def extend (w)
p = @last
np = newState (p.val + 1)
while p! = nil and p.go [w] == nil do
p.go [w] = np
p = p.par
end
if p == nil
np.par = @root
@total + = np.calc # statistics
else
q = p.go [w]
if p.val + 1 == q.val
np.par = q
@total + = np.calc # Statistics
else
nq = newState (p.val + 1)
for i in 0..26 do
nq.go [i] = q.go [i]
end
@total-= q.calc # Statistics
nq.par = q.par
q.par = nq
np.par = nq
@total + = q.calc + nq.calc + np.calc
while p! = nil and p.go [w] == q do
p.go [w] = nq
p = p.par
end
end
end
@last = np
end
end