• CH1402 后缀数组【Hash】【字符串】【二分】


    1402 后缀数组 0x10「基本数据结构」例题

    描述

    后缀数组 (SA) 是一种重要的数据结构,通常使用倍增或者DC3算法实现,这超出了我们的讨论范围。在本题中,我们希望使用快排、Hash与二分实现一个简单的 O(n log^2⁡n ) 的后缀数组求法。详细地说,给定一个长度为 n 的字符串S(下标 0~n-1),我们可以用整数 k(0≤k<n) 表示字符串S的后缀 S(k~n-1)。把字符串S的所有后缀按照字典序排列,排名为 i 的后缀记为 SA[i]。额外地,我们考虑排名为 i 的后缀与排名为 i-1 的后缀,把二者的最长公共前缀的长度记为 Height[i]。我们的任务就是求出SA与Height这两个数组。<n) i="" i-1="" p="">

    输入格式

    一个字符串,长度不超过30万。

    输出格式

    第一行为数组SA,相邻两个整数用1个空格隔开。

    第二行为数组Height,相邻两个整数用1个空格隔开,特别地,假设Height[1]=0。

    样例输入

    ponoiiipoi

    样例输出

    9 4 5 6 2 8 3 1 7 0
    0 1 2 1 0 0 2 1 0 2

    样例解释

    排名第一(最小)的后缀是9(S[9~9],即字符串 i),第二的是后缀4(S[4~9],即字符串iiipoi),第三的是后缀5(S[5~9],即字符串iipoi)以此类推。Height[2]表示排名第2与第1的后缀的最长公共前缀,长度为1,Height[3]表示排名第3与第2的后缀的最长公共前缀,长度为2,以此类推。

    题意:

    给一个字符串s的所有后缀按字典序排个序得到的就是后缀数组。求出排名第i的和排名第i-1的最长公共前缀长度,为height数组

    思路:

    依旧是Hash整个字符串,根据Hash值二分找到两个子串的最长公共子串,以此作为sort的比较依据

    发现大佬们都是不用结构体的,写的很巧妙啊。

    这种方法求后缀数组的复杂度是O(n(logn)^2)

     1 #include <iostream>
     2 #include <set>
     3 #include <cmath>
     4 #include <stdio.h>
     5 #include <cstring>
     6 #include <algorithm>
     7 #include <map>
     8 using namespace std;
     9 typedef long long LL;
    10 #define inf 0x7f7f7f7f
    11 
    12 const int maxn = 3e5 + 10;
    13 char s[maxn];
    14 unsigned long long H[maxn], p[maxn];
    15 int sa[maxn], rk[maxn], height[maxn], n;
    16 
    17 
    18 unsigned long long getH(int i, int j)
    19 {
    20     return H[j] - H[i - 1] * p[j - i + 1];
    21 }
    22 
    23 
    24 //二分求最长公共前缀长度
    25 int lcp(int x, int y)
    26 {
    27     int l = 0, r = min(n - x + 1, n - y + 1);
    28     while(l < r){
    29         int mid = (l + r + 1) / 2;
    30         if(getH(x, x + mid - 1) == getH(y, y + mid - 1)){
    31             l = mid;
    32         }
    33         else{
    34             r = mid - 1;
    35         }
    36     }
    37     return l;
    38 }
    39 
    40 bool cmp(int x, int y)
    41 {
    42     int l = lcp(x, y);
    43     return s[x + l] < s[y + l];
    44 }
    45 
    46 int main()
    47 {
    48     scanf("%s", s + 1);
    49     n = strlen(s + 1);
    50     p[0] = 1;
    51     for(int i = 1; i <= n; i++){
    52         sa[i] = i;
    53         H[i] = H[i - 1] * 131 + s[i] - 'a' + 1;
    54         p[i] = p[i - 1] * 131;
    55     }
    56     sort(sa + 1, sa + n + 1, cmp);
    57     for(int i = 2; i <= n; i++){
    58         height[i] = lcp(sa[i - 1], sa[i]);
    59     }
    60     for(int i = 1; i <= n; i++){
    61         printf("%d ", sa[i] - 1);
    62     }
    63     printf("
    ");
    64     for(int i = 1; i <= n; i++){
    65         printf("%d ", height[i]);
    66     }
    67     printf("
    ");
    68 
    69     return 0;
    70 }
  • 相关阅读:
    perl 解json数组
    华为云3大体系化防护实践,保障金融业云上数据安全
    弹性文件服务解密 -- 块存储、文件存储、对象存储的区别
    【nodejs原理&源码赏析(6)】深度剖析cluster模块源码与node.js多进程
    云+AI+5G时代,华为云已准备好多元化云服务架构
    高能街访 | 为什么他们都纷纷为深圳打Call?
    Angularjs进阶笔记(2)—自定义指令中的数据绑定
    Angularjs进阶笔记(1)—不同类型的双向数据绑定
    ServiceComb java-chassis和CSE java-chassis的区别
    使用inspector功能查看和管理契约
  • 原文地址:https://www.cnblogs.com/wyboooo/p/9820824.html
Copyright © 2020-2023  润新知