Skip to content

Commit d3d2766

Browse files
authored
Merge pull request NASU41#38 from NASU41/StringAlgorithm
NASU41#4 Suffix Arrayの高速化
2 parents 7cc1883 + a61a88d commit d3d2766

1 file changed

Lines changed: 69 additions & 36 deletions

File tree

‎StringAlgorithm/StringAlgorithm.java‎

Lines changed: 69 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,62 +1,95 @@
1+
import java.util.Arrays;
2+
13
class StringAlgorithm {
24
private static int[] saNaive(int[] s) {
35
int n = s.length;
4-
Integer[] _sa = new Integer[n];
5-
for (int i = 0; i < n; i++) {
6-
_sa[i] = i;
6+
int[] sa = new int[n];
7+
for(int i = 0;i < n;i++){
8+
sa[i] = i;
79
}
8-
java.util.Arrays.sort(_sa, (l, r) -> {
10+
insertionsortUsingComparator(sa, (l, r) -> {
911
while (l < n && r < n) {
1012
if (s[l] != s[r]) return s[l] - s[r];
1113
l++;
1214
r++;
1315
}
1416
return -(l - r);
1517
});
16-
int[] sa = new int[n];
17-
for (int i = 0; i < n; i++) {
18-
sa[i] = _sa[i];
19-
}
2018
return sa;
2119
}
2220

2321
private static int[] saDoubling(int[] s) {
2422
int n = s.length;
25-
Integer[] _sa = new Integer[n];
26-
for (int i = 0; i < n; i++) {
27-
_sa[i] = i;
23+
int[] sa = new int[n];
24+
for(int i = 0;i < n;i++){
25+
sa[i] = i;
2826
}
2927
int[] rnk = s;
3028
int[] tmp = new int[n];
3129

3230
for (int k = 1; k < n; k *= 2) {
3331
final int _k = k;
3432
final int[] _rnk = rnk;
35-
java.util.Comparator<Integer> cmp = (x, y) -> {
33+
java.util.function.IntBinaryOperator cmp = (x, y) -> {
3634
if (_rnk[x] != _rnk[y]) return _rnk[x] - _rnk[y];
3735
int rx = x + _k < n ? _rnk[x + _k] : -1;
3836
int ry = y + _k < n ? _rnk[y + _k] : -1;
3937
return rx - ry;
4038
};
41-
java.util.Arrays.sort(_sa, cmp);
42-
tmp[_sa[0]] = 0;
39+
mergesortUsingComparator(sa, cmp);
40+
tmp[sa[0]] = 0;
4341
for (int i = 1; i < n; i++) {
44-
tmp[_sa[i]] = tmp[_sa[i - 1]] + (cmp.compare(_sa[i - 1], _sa[i]) < 0 ? 1 : 0);
42+
tmp[sa[i]] = tmp[sa[i - 1]] + (cmp.applyAsInt(sa[i - 1], sa[i]) < 0 ? 1 : 0);
4543
}
4644
int[] buf = tmp;
4745
tmp = rnk;
4846
rnk = buf;
4947
}
48+
return sa;
49+
}
5050

51-
int[] sa = new int[n];
52-
for (int i = 0; i < n; i++) {
53-
sa[i] = _sa[i];
51+
private static void insertionsortUsingComparator(int[] a, java.util.function.IntBinaryOperator comparator) {
52+
final int n = a.length;
53+
for (int i = 1; i < n; i++) {
54+
final int tmp = a[i];
55+
if (comparator.applyAsInt(a[i - 1], tmp) > 0) {
56+
int j = i;
57+
do {
58+
a[j] = a[j - 1];
59+
j--;
60+
} while (j > 0 && comparator.applyAsInt(a[j - 1], tmp) > 0);
61+
a[j] = tmp;
62+
}
5463
}
55-
return sa;
5664
}
5765

58-
private static final int THRESHOLD_NAIVE = 10;
59-
private static final int THRESHOLD_DOUBLING = 40;
66+
private static void mergesortUsingComparator(int[] a, java.util.function.IntBinaryOperator comparator) {
67+
final int n = a.length;
68+
final int[] work = new int[n];
69+
for (int block = 1; block <= n; block <<= 1) {
70+
final int block2 = block << 1;
71+
for (int l = 0, max = n - block; l < max; l += block2) {
72+
int m = l + block;
73+
int r = Math.min(l + block2, n);
74+
System.arraycopy(a, l, work, 0, block);
75+
for (int i = l, wi = 0, ti = m;; i++) {
76+
if (ti == r) {
77+
System.arraycopy(work, wi, a, i, block - wi);
78+
break;
79+
}
80+
if (comparator.applyAsInt(work[wi], a[ti]) > 0) {
81+
a[i] = a[ti++];
82+
} else {
83+
a[i] = work[wi++];
84+
if (wi == block) break;
85+
}
86+
}
87+
}
88+
}
89+
}
90+
91+
private static final int THRESHOLD_NAIVE = 50;
92+
private static final int THRESHOLD_DOUBLING = 0;
6093

6194
private static int[] sais(int[] s, int upper) {
6295
int n = s.length;
@@ -72,9 +105,9 @@ private static int[] sais(int[] s, int upper) {
72105
if (n < THRESHOLD_NAIVE) {
73106
return saNaive(s);
74107
}
75-
if (n < THRESHOLD_DOUBLING) {
76-
return saDoubling(s);
77-
}
108+
// if (n < THRESHOLD_DOUBLING) {
109+
// return saDoubling(s);
110+
// }
78111

79112
int[] sa = new int[n];
80113
boolean[] ls = new boolean[n];
@@ -195,22 +228,22 @@ public static int[] suffixArray(int[] s, int upper) {
195228
return sais(s, upper);
196229
}
197230

198-
public static int[] suffixArray(int[] s) {
231+
public static int[] suffixArray(int[] s)
232+
{
199233
int n = s.length;
200-
Integer[] idx = new Integer[n];
201-
for (int i = 0; i < n; i++) {
202-
idx[i] = i;
234+
int[] vals = Arrays.copyOf(s, n);
235+
java.util.Arrays.sort(vals);
236+
int p = 1;
237+
for(int i = 1;i < n;i++){
238+
if(vals[i] != vals[i-1]){
239+
vals[p++] = vals[i];
240+
}
203241
}
204-
java.util.Arrays.sort(idx, (l, r) -> s[l] - s[r]);
205242
int[] s2 = new int[n];
206-
int now = 0;
207-
for (int i = 0; i < n; i++) {
208-
if (i > 0 && s[idx[i - 1]] != s[idx[i]]) {
209-
now++;
210-
}
211-
s2[idx[i]] = now;
243+
for(int i = 0;i < n;i++){
244+
s2[i] = java.util.Arrays.binarySearch(vals, 0, p, s[i]);
212245
}
213-
return sais(s2, now);
246+
return sais(s2, p);
214247
}
215248

216249
public static int[] suffixArray(char[] s) {

0 commit comments

Comments
 (0)