POJ2774 --后缀树解法
POJ2774 Long Long Message --后缀树解法
题意明确说明求两字符串的最长连续公共子串,可用字符串hash或者后缀数据结构来做
关于后缀树
后缀树的原理较为简单,但 \(o(n)\) 的构建算法(Ukkonen算法)稍难理解,可参考以下博文
https://www.cnblogs.com/xubenben/p/3484988.html
- 在此也特别感谢该作者,本人也参考了上述文章作者的讲解,可以从我后面的代码看出和作者的代码步骤是一样的。我的代码主要体现的是对本题的dfs阶段的处理
思路
1.获得两个字符串ss1,ss2之后,将其拼接为\(ss1\) + "{" + \(ss1\) + "|",之所以选择这两个字符是因为其ascii码紧跟在'z'之后,对存储空间较为友好
2.对合串建立后缀树
3.遍历后缀树,记录经过的字符串长度,对找到一个经过的长度最长的非叶子节点,这个节点要同时满足:
- 有一个子树中包含{(当然这样的话必然包含|),说明这个节点属于ss1
- 有一个子树中包含|(并且不包含{),说明这个节点属于ss2
同时满足,说明从根到此节点的路程,经过的全是公共子串,可以根据记录的字符串长度更新答案
代码
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <set>
using namespace std;
const int maxn = (1 << 30);
const int root = 1;
char ss[200010] = {0};
char ss2[100005] = {0};
int act = 1, co = 1;
int acteg = -1;
int tep = 0;
int ind = 0, rem = 0, s_end = -1;
int links[100005] = {0};
int vv[100005] = {0};
int mm = 0;
int linkk = 0;
int len1 = 0, len2 = 0;
int ans = 0; //本题答案
struct ab
{
int l;
int r;
int nex;
int alp[28]; // 后面26 27 下标代表的字符是 ‘{’和 ‘|’
} tree[1000005]; // 作为分割与结束符 (ascii相邻防止越界)
int add_new(int o, int ll = s_end, int rr = maxn)
{
tree[o].l = ll;
tree[o].r = rr;
return o;
}
void add_link(int o)
{
if (linkk)
{
tree[linkk].nex = o;
}
linkk = o;
}
int check_len(int o)
{
return min(tree[o].r, s_end) - tree[o].l + 1;
}
bool check_contain(int o)
{
int node_len = check_len(o);
if (node_len <= ind)
{
ind -= node_len;
tep += node_len;
act = o;
return true;
}
return false;
}
void add(char cc)
{
++rem;
linkk = 0;
while (rem > 0)
{
if (!ind)
{
tep = s_end;
}
int& actedge_node = tree[act].alp[ss[tep] - 'a'];
if (!actedge_node)
{
actedge_node = add_new(++co, s_end);
add_link(act);
}
else
{
if (check_contain(actedge_node))
{
continue;
}
else
{
if (ss[tree[actedge_node].l + ind] != cc) // 分裂注意原树(actedge_node)必须成为子树(否则会和原先的子树失去联系)
{
int leaf1 = add_new(++co, s_end);
int leaf2 = actedge_node;
int newtree = add_new(++co, tree[actedge_node].l, tree[actedge_node].l + ind - 1);
tree[newtree].alp[cc - 'a'] = leaf1;
tree[newtree].alp[ss[tree[actedge_node].l + ind] - 'a'] = leaf2;
tree[leaf2].l += ind;
actedge_node = newtree;
add_link(actedge_node);
}
else
{
++ind; // 活跃半径只在此处增加 ,增加完就加链并结束本次增点
// if (act != root)
// {
add_link(act);
// }
break;
}
}
}
--rem;
if (act == root)
{
if (!ind)
{
break;
}
tep = s_end - rem + 1;
--ind;
}
else
{
// ind = rem - 1;
// tep = s_end - rem + 1;
if (tree[act].nex)
{
act = tree[act].nex;
}
else
{
act = root;
}
}
}
}
int dfs(int o, int cc) // 本题所需的搜索 返回1代表包含{,2代表包含|,3代表都有
{
bool bk1 = false;
bool bk2 = false;
bool stop = false;
for (int i = 0; i <= 27; ++i)
{
if (tree[o].alp[i])
{
if (tree[tree[o].alp[i]].r != maxn)
{
int contain_terminal = dfs(tree[o].alp[i], cc + check_len(tree[o].alp[i]));
if (contain_terminal == 1)
{
bk1 = true;
}
if (contain_terminal == 2)
{
bk2 = true;
}
if (contain_terminal == 3)
{
bk1 = bk2 = true;
stop = true;
}
}
else
{
if (tree[tree[o].alp[i]].l > len1)
{
bk2 = true;
}
else
{
bk1 = true;
}
}
}
}
if (stop)
{
return 3;
}
if (bk1 && bk2)
{
ans = max(ans, cc);
return 3;
}
if (bk1)
{
return 1;
}
if (bk2)
{
return 2;
}
}
int main()
{
scanf("%s%s", ss, ss2);
len1 = strlen(ss);
len2 = strlen(ss2);
ss[len1] = '{'; //ss1的结束符,防止两字符串后缀拼接
for (int i = len1 + 1; i <= len1 + len2; ++i)
{
ss[i] = ss2[i - len1 - 1];
}
ss[len1 + len2 + 1] = '|'; //ss2的结束符(也是整个合串的结束符)
for (int i = 0; i <= len1 + len2 + 1; ++i)
{
++s_end;
add(ss[i]);
}
dfs(root, 0);
printf("%d", ans);
return 0;
}
POJ2774 --后缀树解法的更多相关文章
- 从Trie树(字典树)谈到后缀树
转:http://blog.csdn.net/v_july_v/article/details/6897097 引言 常关注本blog的读者朋友想必看过此篇文章:从B树.B+树.B*树谈到R 树,这次 ...
- [算法]从Trie树(字典树)谈到后缀树
我是好文章的搬运工,原文来自博客园,博主July_,地址:http://www.cnblogs.com/v-July-v/archive/2011/10/22/2316412.html 从Trie树( ...
- 笔试算法题(40):后缀数组 & 后缀树(Suffix Array & Suffix Tree)
议题:后缀数组(Suffix Array) 分析: 后缀树和后缀数组都是处理字符串的有效工具,前者较为常见,但后者更容易编程实现,空间耗用更少:后缀数组可用于解决最长公共子串问题,多模式匹配问题,最长 ...
- BZOJ 3238: [Ahoi2013]差异((单调栈+后缀数组)/(后缀树))
[传送门[(https://www.lydsy.com/JudgeOnline/problem.php?id=3238) 解题思路 首先原式可以把\(len\)那部分直接算出来,然后通过后缀数组求\( ...
- 后缀树(suffix tree)
参考: 从前缀树谈到后缀树 后缀树 Suffix Tree-后缀树 字典树(trie树).后缀树 一.前缀树 简述:又名单词查找树,tries树,一种多路树形结构,常用来操作字符串(但不限于字符串), ...
- 字符串 --- KMP Eentend-Kmp 自动机 trie图 trie树 后缀树 后缀数组
涉及到字符串的问题,无外乎这样一些算法和数据结构:自动机 KMP算法 Extend-KMP 后缀树 后缀数组 trie树 trie图及其应用.当然这些都是比较高级的数据结构和算法,而这里面最常用和最熟 ...
- 后缀树系列一:概念以及实现原理( the Ukkonen algorithm)
首先说明一下后缀树系列一共会有三篇文章,本文先介绍基本概念以及如何线性时间内构件后缀树,第二篇文章会详细介绍怎么实现后缀树(包含实现代码),第三篇会着重谈一谈后缀树的应用. 本文分为三个部分, 首先介 ...
- 【Todo】字符串相关的各种算法,以及用到的各种数据结构,包括前缀树后缀树等各种树
另开一文分析字符串相关的各种算法,以及用到的各种数据结构,包括前缀树后缀树等各种树. 先来一个汇总, 算法: 本文中提到的字符串匹配算法有:KMP, BM, Horspool, Sunday, BF, ...
- [转载]字典树(trie树)、后缀树
(1)字典树(Trie树) Trie是个简单但实用的数据结构,通常用于实现字典查询.我们做即时响应用户输入的AJAX搜索框时,就是Trie开始.本质上,Trie是一颗存储多个字符串的树.相邻节点间的边 ...
随机推荐
- 黎活明8天快速掌握android视频教程--16_采用SharedPreferences保存用户偏好设置参数
SharedPreferences保存的数据是xml格式,也是存在数据保存的下面四种权限: 我们来看看 我们来看看具体的业务操作类: /** * 文件名:SharedPrecences.java * ...
- ECSHOP 2.5.1 二次开发文档【文件结构说明和数据库表分析】
ecshop文件架构说明 /* ECShop 2.5.1 的结构图及各文件相应功能介绍 ECShop2.5.1_Beta upload 的目录 ┣ activity.php 活动列表 ┣ affich ...
- 发布Nuget包时遇到都意外
准备好工具和发布教程.(这些网上都有,我就不说了,就说说我遇到都意外.) 在发布包都过程中,我给我都dll命名为Common.不知道是不是这个原因导致的我包发布上去后,程序对其引用时居然没主动引用进程 ...
- vim/vm命令后提示错误:Found a swap file by the name ".dockerfile.swp"
今天在使用docker时,使用vim命令操作dockerfile文件,提示如下错误: 错误原因,是由于上一次在操作该文件时,异常退出,然后系统生成了一个dockerfile.swp文件,该文件是个隐藏 ...
- java.math.BigDecimal cannot be cast to [Ljava.lang.Object;
从数据库中使用sum函数取出统计值后,放进list中,遍历list的时候强转化成Object是报错. BigDecimal .Integer不是基本类型,是int的包装类,无法把包装当做基本类型来用. ...
- 二.httpRequest-httpResponse-JsonResponse对象
一.HttpRequest对象 HttpRequest在django.http这个模块中 它是用django创建 文档https://docs.djangoproject.com/en/1.11/r ...
- 认识Eureka (F版)
Spring Cloud 为开发者提供了在分布式系统中的一些常用的组件(例如配置管理,服务发现,断路器,智能路由,微代理,控制总线,一次性令牌,全局锁定,决策竞选,分布式会话集群状态).使用Sprin ...
- C#由转换二进制所引起的思考,了解下?
前言 最近遇到很有意思转换二进制的问题,有部分童鞋俨然已了解,可能也有一部分童鞋没碰到过也就不知情,这里我们来深入学习下转换二进制所带来的问题. 二进制转换问题 假设现在我们有一个int类型的数据,它 ...
- 【经验】GaussDB(for MySQL)性能优化 —— 日志的“快递驿站”
GaussDB(for MySQL)数据库在写入性能上,在业界同类产品中是最好的,这主要得益于GaussDB(for MySQL)在MySQL内核方面的诸多优化.其中有一项从“送快递”得来灵感的优化— ...
- java语言基础(二)_IDEA_方法
IDEA使用 项目结构: 所有代码放置在src文件夹内 新建包:在src文件夹上,右键新建包.包的命名:英文小写.数字.英文句点. 例如:使用公司域名倒写,如cn.itcast.day04.demo0 ...