zoukankan      html  css  js  c++  java
  • Suffix Array 后缀数组

    后缀数组


    顾名思义。SuffixArray(下面有时简称SA) 和字符串的后缀有关。

    后缀:字符串中某个位置一直到结尾的子串。(SA中讨论包含了原串和空串)。所以共同拥有len+1个后缀。

    后缀数组: 字符串的全部后缀组成的按字典序从小到大排好的数组。因为SA中记录的都是字符串的后缀,所以SA仅仅须要记录其表示的后缀的起始位置。

    因为比較字典序是O(n)的,所以暴力算法的复杂度将是O(n^2logn)。通过一些算法能够降到线性复杂度。这里先介绍一种简单的O(nlognlogn)的算法。



    该算法的思想是通过倍增法减少了比較字典序的大小的复杂度O(n)到O(logn)。

    其求解时不先算后缀,而是先算长度为1的子串的字典序大小排列,然后得到一个rank数组,即该子串在全部子串中排位的值。字典序越小,rank值越小。


    rank[k][i] 表示起始位置为i的长度为k的子串在全部长度为k的子串中的字典序大小。


    这时我们要比較长度为2k的子串的大小的话。其第i个位置的长度为2k的子串的大小能够通过比較rank[k][i]和rank[k][i+k]来实现。



    SA中的sa[i]表示字典序位i的后缀串的起始位置。


    const int MAXN = 100000 + 5;
    int _k, _len;
    int _rank[MAXN];
    int _tmp[MAXN];
    int _sa[MAXN];// 后缀数组。

    bool _cmp(int i, int j) { if (_rank[i] == _rank[j]) { int _ri = (i+_k <= _len) ? _rank[i+_k] : -1; int _rj = (j+_k <= _len) ? _rank[j+_k] : -1; return _ri < _rj; } else { return _rank[i] < _rank[j]; } } void Suffix_sa(string s, int* sa) { _len = s.size(); for (int i=0; i<_len; i++) { sa[i] = i; _rank[i] = s[i]; } sa[_len] = _len; _rank[_len] = -1; for ( _k=1; _k<=_len; _k<<=1) { sort(sa, sa+_len+1, _cmp); _tmp[sa[0]] = 0; for (int i=1; i<=_len; i++) { _tmp[sa[i]] = _tmp[sa[i-1]]; if (_cmp(sa[i-1], sa[i])) { _tmp[sa[i]]++; } } copy(_tmp, _tmp+_len+1, _rank); } }



  • 相关阅读:
    Java读书笔记
    b_aw_旅游计划(树的中心变形)
    b_lc_秋叶收集器(分类讨论dp+滚动数组优化)
    b_lg_涂色(从小区间做起,讨论s[l]和s[r]的关系)
    c_lc_早餐组合(排序+双指针)
    c_aw_鱼塘钓鱼(大根堆)
    b_pat_栈(2*multiset+stack)
    c_pat_推荐系统(set模拟)
    b_lg_时态同步(后序遍历统计每棵子树的最大高度)
    b_lc_统计不开心的朋友(预处理+模拟)
  • 原文地址:https://www.cnblogs.com/liguangsunls/p/7199022.html
Copyright © 2011-2022 走看看