-
Notifications
You must be signed in to change notification settings - Fork 74
/
suffix_array_long.py
82 lines (58 loc) · 1.93 KB
/
suffix_array_long.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# python3
import sys
def sort_characters(text):
order = [0] * len(text)
char_set = sorted(set(text))
count = [text.count(c) for c in char_set]
for i in range(1, len(count)):
count[i] += count[i - 1]
for i, c in reversed(list(enumerate(text))):
count[char_set.index(c)] -= 1
order[count[char_set.index(c)]] = i
return order
def compute_char_classes(text, order):
clss = [0] * len(text)
for i in range(1, len(text)):
if text[order[i]] != text[order[i - 1]]:
clss[order[i]] = clss[order[i - 1]] + 1
else:
clss[order[i]] = clss[order[i - 1]]
return clss
def sort_doubled(text, l, order, clss):
len_text = len(text)
count = [0] * len_text
new_order = [0] * len_text
for i in range(len_text):
count[clss[i]] += 1
for j in range(1, len_text):
count[j] += count[j - 1]
for i in range(len_text - 1, -1, -1):
start = (order[i] - l + len_text) % len_text
cl = clss[start]
count[cl] -= 1
new_order[count[cl]] = start
return new_order
def update_classes(new_order, clss, l):
n = len(new_order)
new_clss = [0] * n
for i in range(1, n):
cur, prev = new_order[i], new_order[i - 1]
mid, mid_prev = cur + l, (prev + l) % n
if clss[cur] != clss[prev] or clss[mid] != clss[mid_prev]:
new_clss[cur] = new_clss[prev] + 1
else:
new_clss[cur] = new_clss[prev]
return new_clss
def build_suffix_array(text):
order = sort_characters(text)
clss = compute_char_classes(text, order)
length = 1
len_text = len(text)
while length < len_text:
order = sort_doubled(text, length, order, clss)
clss = update_classes(order, clss, length)
length = length * 2
return order
if __name__ == '__main__':
text = sys.stdin.readline().strip()
print(" ".join(map(str, build_suffix_array(text))))