@@ -42,7 +42,6 @@ inline void _InducedSort(const std::vector<long> &str,
4242 // 为了方便抄板子, 我这里先把一些变量提取出来.
4343 // 开销应该不大, 因为估计编译器一下就给消掉了.
4444 const long n = str.size (), max_val = buckets.size () - 1 ;
45-
4645 // 从左向右扫描SA数组,
4746 // 这里的目标是从LMS进行L诱导.
4847 // 然后把L放到每个桶的头部.
@@ -59,7 +58,6 @@ inline void _InducedSort(const std::vector<long> &str,
5958 prev_bucket.left ++;
6059 }
6160 }
62-
6361 // 将桶的底部重置, 这里的意思是删除那些LMS.
6462 // 删除掉LMS之后, 再根据之前放入的L的字符,
6563 // 诱导出所有的S的字符的位置.
@@ -71,7 +69,6 @@ inline void _InducedSort(const std::vector<long> &str,
7169 // 也就意味着这个桶满了.
7270 buckets[i].right = prefix_sums[i] - 1 ;
7371 }
74-
7572 // 从右往左扫描.
7673 // 这次扫描要把S类型的字符放进桶.
7774 for (long i = n - 1 ; i >= 0 ; i--) {
@@ -88,7 +85,6 @@ inline void _InducedSort(const std::vector<long> &str,
8885 }
8986 }
9087}
91-
9288// str必须是已经被处理好的, 确认了最后的数字是全局唯一最小的哨兵的串.
9389// max_val可以给的稍微大一点也没关系.
9490inline std::vector<long > _SAIS (const std::vector<long > &str,
@@ -103,21 +99,17 @@ inline std::vector<long> _SAIS(const std::vector<long> &str,
10399 // str[i] < str[i + 1], 记作S,
104100 // str[i] == str[i + 1], type[i] = type[i + 1].
105101 std::vector<Type> type (str.size (), S_TYPE);
106-
107102 // 这里因为建立桶的需求,
108103 // 所以需要统计每个字符在这里都出现了几次.
109104 // 因为我们两次诱导排序,
110105 // 使用的是同一个串, 所以我们就不再排序的过程中扫描这个了哈.
111106 std::vector<long > cnt_occurance (max_val + 1 , 0 );
112-
113107 // 尾部字符单独统计,
114108 // 因为下面扫描全字符串是从倒数第二个字符开始的.
115109 cnt_occurance[str.back ()]++;
116-
117110 // 收集所有LMS的下标.
118111 std::vector<long > lms_incidies;
119112 lms_incidies.reserve (str.size () / 2 );
120-
121113 // 逆序遍历字符串, 获取类型.
122114 // 这里逆序遍历的原因是, 如果
123115 // str[i] == str[i + 1], 那么则有:
@@ -140,11 +132,9 @@ inline std::vector<long> _SAIS(const std::vector<long> &str,
140132 } else {
141133 assert (false );
142134 }
143-
144135 // 记录出现次数.
145136 cnt_occurance[str[i]]++;
146137 }
147-
148138 // 创建前缀和数组, 为建立桶和诱导排序做准备.
149139 std::vector<long > prefix_sums (max_val + 2 );
150140 std::partial_sum (cnt_occurance.begin (), cnt_occurance.end (),
@@ -158,7 +148,6 @@ inline std::vector<long> _SAIS(const std::vector<long> &str,
158148 buckets[i].left = prefix_sums[i - 1 ];
159149 buckets[i].right = prefix_sums[i] - 1 ;
160150 }
161-
162151 // 放入LMS.
163152 // 这里对于同一个字母, 入桶的顺序应该是倒序的.
164153 // 这个似乎和诱导排序的实现有关系.
@@ -169,19 +158,15 @@ inline std::vector<long> _SAIS(const std::vector<long> &str,
169158 auto curr_idx = *it;
170159 auto curr_char = str[curr_idx];
171160 auto &curr_bucket = buckets[curr_char];
172-
173161 // 将对应的下标放入桶中.
174162 SA[curr_bucket.right ] = curr_idx;
175163 curr_bucket.right --;
176164 }
177-
178165 // 进行第一次诱导排序.
179166 _InducedSort (str, type, SA, prefix_sums, buckets);
180-
181167 // 创建名字和下标的对应关系.
182168 // 这里用names数组表达对应位置的名字.
183169 std::vector<long > names (str.size (), -1 );
184-
185170 // 这两个变量分别记录了下发的名字的数量,
186171 // 和上一个被探测到的LMS的坐标.
187172 long name_cnt = 0 ;
@@ -203,7 +188,6 @@ inline std::vector<long> _SAIS(const std::vector<long> &str,
203188 return false ;
204189 }
205190 };
206-
207191 // 这里的这个函数是用来比较两个LMS子串是否相等的.
208192 const auto is_lms_eq = [&](const unsigned long idx1,
209193 const unsigned long idx2) -> bool {
@@ -217,7 +201,6 @@ inline std::vector<long> _SAIS(const std::vector<long> &str,
217201 if (idx1 == str.size () - 1 || idx2 == str.size () - 1 ) {
218202 return false ;
219203 }
220-
221204 // 从偏移量为0开始比较
222205 long offset = 0 ;
223206 do {
@@ -229,18 +212,15 @@ inline std::vector<long> _SAIS(const std::vector<long> &str,
229212 if (type[idx1 + offset] != type[idx2 + offset]) {
230213 return false ;
231214 }
232-
233215 // 手动更新偏移量
234216 offset++;
235217 // 循环条件: 两个待比较位置都没有来到下一个LMS
236218 } while (!is_lms (idx1 + offset) && !is_lms (idx2 + offset));
237-
238219 // 如果有一个没有到达下一个LMS但是另外一个到达,
239220 // 那么二者一定不相等.
240221 if (!is_lms (idx1 + offset) || !is_lms (idx2 + offset)) {
241222 return false ;
242223 }
243-
244224 // 否则还是比较这两个LMS对应的字符.
245225 if (str[idx1 + offset] != str[idx2 + offset]) {
246226 return false ;
@@ -250,7 +230,6 @@ inline std::vector<long> _SAIS(const std::vector<long> &str,
250230 }
251231 return true ;
252232 };
253-
254233 // 这个时候, it是当前正在处理的的lms下标
255234 if (is_lms (it)) {
256235 // 如果上一个LMS存在,
@@ -271,13 +250,11 @@ inline std::vector<long> _SAIS(const std::vector<long> &str,
271250 // 那么肯定要分配一个新名字.
272251 name_cnt++;
273252 }
274-
275253 // 将名字下发下去.
276254 names[it] = name_cnt - 1 ;
277255 last_lms_idx = it;
278256 }
279257 }
280-
281258 // 命名唯一, 无需递归,
282259 // 直接返回.
283260 if (static_cast <unsigned long >(name_cnt) == lms_incidies.size ()) {
@@ -296,10 +273,8 @@ inline std::vector<long> _SAIS(const std::vector<long> &str,
296273 auto curr_lms_idx = lms_incidies[i];
297274 lms_str[i] = names[curr_lms_idx];
298275 }
299-
300276 // 最大的一个名字是最大的name_cnt - 1.
301277 lms_SA = _SAIS (lms_str, name_cnt - 1 );
302-
303278 // 生成一个新的桶并清空SA数组,
304279 // 进行第二次诱导排序.
305280 std::fill (SA.begin (), SA.end (), -1 );
@@ -308,7 +283,6 @@ inline std::vector<long> _SAIS(const std::vector<long> &str,
308283 buckets[i].left = prefix_sums[i - 1 ];
309284 buckets[i].right = prefix_sums[i] - 1 ;
310285 }
311-
312286 // 这里倒序遍历, 同时将遍历到的位置放在桶对应字母的右侧.
313287 // 因此可以保证lms_SA中靠右的下标会优先被处理后放入桶的右侧.
314288 // 因此对于同一个字母, lms_SA中靠右的在桶中也靠右.
@@ -321,19 +295,15 @@ inline std::vector<long> _SAIS(const std::vector<long> &str,
321295 // 存放的那个lms的名字对应的下标,
322296 // 就是lms_incidies[lms_SA[i]]中存放的那个下标.
323297 auto curr_lms_idx = lms_incidies[lms_SA[i]];
324-
325298 // 同样地获取桶
326299 auto curr_char = str[curr_lms_idx];
327300 auto &curr_bucket = buckets[curr_char];
328-
329301 // 将下标放在桶的右侧.
330302 SA[curr_bucket.right ] = curr_lms_idx;
331303 curr_bucket.right --;
332304 }
333-
334305 // 第二次诱导排序.
335306 _InducedSort (str, type, SA, prefix_sums, buckets);
336-
337307 return SA;
338308 }
339309}
@@ -350,7 +320,6 @@ std::vector<unsigned long> BuildSuffixArray(const Container &str) {
350320 if (processed[i] > max_val) max_val = processed[i];
351321 }
352322 processed.back () = 0 ; // 哨兵,唯一且最小
353-
354323 auto res = _SAIS (processed, max_val);
355324 // res[0] 对应哨兵的位置 (通常是 processed.size() - 1)
356325 std::vector<unsigned long > processed_res (std::next (res.begin ()), res.end ());
@@ -368,7 +337,6 @@ std::vector<unsigned long> suffix_array(Container &&str) {
368337 if (processed[i] > max_val) max_val = processed[i];
369338 }
370339 processed.back () = 0 ; // 哨兵,唯一且最小
371-
372340 auto res = _SAIS (processed, max_val);
373341 // res[0] 对应哨兵的位置 (通常是 processed.size() - 1)
374342 std::vector<unsigned long > processed_res (std::next (res.begin ()), res.end ());
0 commit comments