最长公共子串(后缀数组)_最长公共子串 后缀数组-程序员宅基地

技术标签: 动态规划DP  



题目:http://poj.org/problem?id=2217

首先解释,DP中的最长公共子序列和此处的最长公共子串区别-------------------序列可以是不连续的,但是子串是连续的

其次,LCP,lcp[i]就是lcp[rank[i]]和lcp[rank[i]+1]的最长公共前缀,那么把两个字符串接起来,然后找最长的lcp,就是答案


思路还是比较清晰的


上代码:

  1. /*******************************************************/  
  2. //poj 2217 lcp+sa by Pilgrim  
  3. //最长公共子串---注意与动态规划的最长公共子序列不同  
  4. //2014.4.2  
  5. /******************************************************/  
  6.   
  7. #include <string>  
  8. #include <cstring>  
  9. #include <cstdio>  
  10. #include <algorithm>  
  11. #include <iostream>  
  12. #include <cstdlib>  
  13. #include <vector>  
  14.   
  15. #define MAXN 10010  
  16. #define INF 0x80000000  
  17. //0x7fffffff  
  18. //0x80000000  
  19.   
  20. using namespace std;  
  21.   
  22. int n,k;//n=strlen(s);  
  23.   
  24. int Rank[MAXN];  
  25. int tmp[MAXN];  
  26.   
  27. /*使用Rank对sa排序*/  
  28. bool cmpSa(int i, int j)  
  29. {  
  30.     if(Rank[i] != Rank[j])return Rank[i] < Rank[j];  
  31.     else  
  32.     {   /*下面的Rank[t],已经是以t开头长度小于等于k/2的, 
  33.         sa[i]的名次,只是以i开头的后缀,而长度不同*/  
  34.         int ri = i+k <=n? Rank[i+k]:-1;  
  35.         int rj = j+k <= n ? Rank[j+k]:-1;  
  36.         return ri <rj;  
  37.     }  
  38. }  
  39.   
  40. /*计算SA*/  
  41. void con_sa(char *s, int *sa)  
  42. {  
  43.     /*n=strlen(s);  必要时注明*/  
  44.     /*初始化sa和rank保证两点 
  45.         1、Rank[i]表示下标为i的是第几大,必须表示出相对大小,可以直接用字符代表其大小 
  46.         2、sa[1...n]值为1..n*/  
  47.     for(int i=0;i<=n;i++){  
  48.         sa[i]=i;Rank[i] = i < n?s[i]:-1;  
  49.     }  
  50.   
  51.     /*利用长度为k的字符串对长度为2*k的字符串排序*/  
  52.     for(k=1;k<=n;k*=2)/*注意此代码中k是全局变量 别乱用,循环必须从1开始,因为0*2=0*/  
  53.     {  
  54.         sort(sa,sa+n+1,cmpSa);  
  55.         tmp[sa[0]] = 0; /*此时tmp只是暂存rank*/  
  56.         for(int i=1;i<=n;i++){  
  57.             tmp[sa[i]] = tmp[sa[i-1]] +(cmpSa(sa[i-1],sa[i])?1:0);  
  58.             /*这一句很关键,等号右侧的sa[i]在此循环里表示第i大的长度小于等于k/2的字符串, 
  59.               从而求出第i大的长度小于等于k的字符串的sa[i]*/  
  60.         }  
  61.         for(int i=0;i<=n;i++){  
  62.             Rank[i] = tmp[i];  
  63.         }  
  64.     }  
  65. }  
  66.   
  67. void construct_lcp(char *s,int *sa,int *lcp)  
  68. {  
  69.     //n=strlen(s);  
  70.     for(int i=0; i<=n; i++)Rank[sa[i]]=i;  
  71.   
  72.     int h=0;  
  73.     lcp[0]=0;  
  74.     for(int i=0;i<n;i++)  
  75.     {  
  76.         int j=sa[Rank[i]-1];  
  77.   
  78.         if(h>0)h--;  
  79.         for(; j+h<n && i+h<n; h++)  
  80.         {  
  81.             if(s[j+h]!=s[i+h])break;  
  82.         }  
  83.         lcp[Rank[i]-1]=h;  
  84.     }  
  85. }  
  86.   
  87.   
  88. int main()  
  89. {  
  90.     int sa[MAXN],lcp[MAXN];  
  91.     char s[MAXN],t[MAXN];  
  92.     char c;  
  93.     int ncase,mmax,len,leng;  
  94.   
  95.     while(scanf("%d",&ncase)!=EOF)  
  96.     {  
  97.         while(ncase--)  
  98.         {  
  99.             mmax =0;  
  100.             while((c=getchar())==' '|| c=='\n');  
  101.             s[0]=c;  
  102.             int tt=1;  
  103.             while((c=getchar()) != '\n')  
  104.             {  
  105.                 s[tt++]=c;  
  106.   
  107.             }  
  108.   
  109.             s[tt]='\0';  
  110.             while((c=getchar())==' '|| c=='\n');  
  111.             t[0]=c;  
  112.             tt=1;  
  113.             while((c=getchar()) != '\n')  
  114.             {  
  115.                  t[tt++]=c;  
  116.   
  117.             }  
  118.             t[tt]='\0';  
  119.             len=strlen(s);  
  120.             leng =len+1+strlen(t);  
  121.             strcpy(s+len+1,t);  
  122. ///  
  123. //for(int i=0;i<leng;i++)  
  124.  //   putchar(s[i]);  
  125. //putchar('\n');  
  126.             n=leng;  
  127.             con_sa(s,sa);  
  128.             construct_lcp(s,sa,lcp);  
  129.   
  130.            for(int i=0;i<leng;i++)  
  131.             {  
  132.               if((sa[i]<len) != (sa[i+1]<len))  
  133.                   mmax=max(mmax,lcp[i]);  
  134.             }  
  135.             printf("Nejdelsi spolecny retezec ma delku %d.\n",mmax);  
  136.         }  
  137.     }  
  138.   
  139.     return 0;  
  140. }  

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/briup_acmer/article/details/45166255

智能推荐

Sample Probability Space_probability space例题-程序员宅基地

文章浏览阅读66次。Sample Probability SpaceA simple probability space consist of a tuple (Ω\OmegaΩ,ε\varepsilonε,p)Ω\OmegaΩ is a finite set (with cardinality k= ∣\mid∣Ω\OmegaΩ∣\mid∣)ε\varepsilonε = { A : A ⊆\subseteq⊆ Ω\OmegaΩ } consist of all finite subsetsEach events _probability space例题

python分布式服务系统框架_Cola:一个分布式爬虫框架 - 系统架构 - Python4cn(news, jobs)...-程序员宅基地

文章浏览阅读348次。由于早先写的WeiboCrawler问题很多,而且当时我有提到,其实可以实现一个通用的爬虫框架。最近由于要抓取新的数据,于是我就写了这个cola。下面的文字来自wiki。Cola是一个分布式的爬虫框架,用户只需编写几个特定的函数,而无需关注分布式运行的细节。任务会自动分配到多台机器上,整个过程对用户是透明的。依赖由于Cola配置文件使用的yaml,所以Cola只依赖于pyyaml,安装easy_i..._cola爬虫

名悦集团国庆出行自驾游攻略-程序员宅基地

文章浏览阅读75次。在这个买车已经不是什么难事的年代,大多数人出行都会选择自驾方式,但自驾出游必然要面临一系列的问题以及做足准备工作。名悦集团小编给大家总结出了这次国庆假期出行自驾游攻略,为了保证自驾过程的安全顺利,玩得更加痛快,临行前的车辆检查时必不可少的,这些项目可以自己检查,如果实在是懒或者不懂,可以在临行前去4S店做个基础保养,以让爱车在最佳车况陪伴自己和家人朋友开始这段愉快的旅程。1.轮胎轮胎的检查是自驾前需要关键的检查之一,在自驾的旅程上不管是轮胎没气还是爆胎,都是非常令人揪心的,如果是在高速或者...

Android 输入法框架源码分析总结(1)_android 输入法源码-程序员宅基地

文章浏览阅读3.6k次,点赞3次,收藏7次。参考文档 https://blog.csdn.net/huangyabin001/article/details/28434989https://blog.csdn.net/huangyabin001/article/details/28435093#commentshttps://blog.csdn.net/jieqiong1/article/details/712629871..._android 输入法源码

Ubuntu下使用nnUNet 训练自己的数据集(只管实现,不讲原理,通俗易懂)_nnunet训练自己的数据集-程序员宅基地

本文介绍了如何在Ubuntu下使用nnUNet训练自己的数据集,不涉及原理解析,只提供实现步骤。包括nnUNet简介、修改训练参数和文件位置等操作。详细内容可参考Tina的博文。

SSM实现秒杀系统案例-程序员宅基地

文章浏览阅读9.9k次,点赞10次,收藏88次。对于抢购系统来说,首先要有可抢购的活动,而且这些活动具有促销性质,这种大型活动的负载可能是平时的几十倍,所以通过增加硬件、优化瓶颈代码等手段是很难达到目标的,所以抢购系统得专门设计。在这里我们说的库存不是真正意义上的库存,其实是该促销可以抢购的数量,真正的库存在基础库存服务。用户点击『提交订单』按钮后,在抢购系统中获取了资格后才去基础库存服务中扣减真正的库存;而抢购系统控制的就是资格/剩余数。传统方案利用数据库行锁,但是在促销高峰数据库压力过大导致服务不可用,目前采用redis集群(16分片)缓存促销信息,

随便推点

正则表达式匹配各种括号内内容_正则表达式 匹配多个括号-程序员宅基地

文章浏览阅读2.8w次,点赞10次,收藏9次。用正则表达式匹配两个字符中间的文本String skh ="(?<=\\《)[^\\》]+";//用于匹配《》里面的文本String str="但实际上《kajdwdej》孙大伟多";//测试字符串Pattern pattern=Pattern.compile(skh); Matcher matcher=pattern.matcher(str); boolean is=matche_正则表达式 匹配多个括号

Android 中的Shape_linear radial sweep分别代表的什么-程序员宅基地

文章浏览阅读553次。之前一直看项目用过这个东西,但是自己都不怎么熟悉,大概就知道可以画一些圆角之类的~ 今天就来好好了解一下吧~Shape里面有很多属性,依次学习一下第一步~首先来写一个Button这个布局文件就不贴了...太简单了~ (PS:说贴出来的站出来,我保证不打死你!)接下来开始学习第一个属性:Solid:(填充)在Drawable里面创建一个butt_linear radial sweep分别代表的什么

graphpad细胞增殖曲线_如何用GraphPad Prism绘制剂量反应曲线?-程序员宅基地

文章浏览阅读6.1k次。上图是Sci文献中的dose–response curves (剂量反应曲线),横坐标是药物GS-Se-SG浓度的对数值,纵坐标是Rrelative cell viability(相对细胞活性,% of control),从图注中可以知道IC50为5.1 μM。那么什么是IC50呢?IC50 (half maximal inhibitory concentration)是指被测量的拮抗剂的半抑制浓..._graphpad细胞增殖曲线

二叉查找树(非递归、递归遍历)_二叉排序树非递归查找-程序员宅基地

文章浏览阅读658次。二叉查找树(含递归、非递归遍历)_二叉排序树非递归查找

spark-sql 查询报错:Invalid method name: ‘get_table_req‘_invalid method name: 'get_table_req-程序员宅基地

文章浏览阅读3.1k次。spark-sql> select * from zps_d001 limit 1;Error in query: org.apache.hadoop.hive.ql.metadata.HiveException: Unable to fetch table zps_xxx. Invalid method name: 'get_table_req'org.apache.spark.sql.AnalysisException: org.apache.hadoop.hive.ql.metadata.H_invalid method name: 'get_table_req

unknown mutation type:-程序员宅基地

文章浏览阅读1.7w次。我这边使用得是vue+elementvue得状态组成actions 这个是异步请求 通过异步请求得话 然后在调用 mutations.jsmutations.js 将数据提交到这里 this.$commit(‘test’,testTemp)index.js 这个是将数据初始化getters 这个是将 this.$store.getters.test 就能获取到了 testTemp写法是这个写法最后得原因是因为我这在 index.js 和mutation.js 为定义常量##_unknown mutation type

推荐文章

热门文章

相关标签