后缀自动机的python实现
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Date : 2019-02-25 14:32:50
# @Author : Sheldon (thisisscret@qq.com)
# @Blog : 谢耳朵的派森笔记
# @Link : https://www.cnblogs.com/shld/
# @Version : 0.0.1
from collections import OrderedDict
import logging
from copy import deepcopy logger = logging.getLogger("sam")
logger.propagate = False
logger.handlers.clear()
logger.setLevel(level=logging.INFO)
# handler = logging.FileHandler("log.txt")
handler = logging.StreamHandler()
handler.setLevel(logging.INFO)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)
logger.addHandler(handler) class State:
def __init__(self, length=None, link=None, trans=None):
self.length = length
self.link = link
self.trans = trans class Sam:
def __init__(self, s=""):
self.last = 0
self.sz = 1
self.st = OrderedDict({0: State(0, -1, OrderedDict())})
self.samstr = ""
self(s) @staticmethod
def _dict2str(dct):
return ' '.join(f'{k}->{w}' for k, w in dct.items()) def _extend(self, c):
cur = self.sz self.st[cur] = State(None, None, OrderedDict())
self.st[cur].length = self.st[self.last].length + 1
logger.debug(f"状态{cur}添加到后缀自动机")
logger.debug(f"上一个节点状态是{self.last}")
logger.debug(f"状态{cur}的长度是{self.st[self.last].length + 1}") # 如果后缀自动机最近转移里面没有当前字符,则添加该字符,并将状态指向当前状态
# 继续沿着后缀连接走,进行上述操作直到到达第一个状态或者转移中有此字符
p = self.last while p > -1 and self.st[p].trans.get(c) is None:
logger.debug(
f"状态{p}的转移:{self._dict2str(self.st[p].trans)}{('','不')[self.st[p].trans.get(c) is None]}包含字符{c}") self.st[p].trans[c] = cur
logger.debug(f"把{c}添加进状态{p}的转移")
logger.debug(f"开始查找状态{p}的后缀链接...")
p = self.st[p].link
logger.debug(f"后缀链接为状态{p}") # 如果后缀链接走到底了,没有相同的,则后缀链接指向0状态,即空字符串
if p == -1:
self.st[cur].link = 0
logger.debug(f"状态{cur}沿后缀链接走到了初始状态,将其的后缀链接指向状态0") # 如果找到上一状态的转移里有c字符,找到转移c的另一状态
else:
q = self.st[p].trans[c]
logger.debug(f"在状态{p}的转移中找到了字符{c},{c}指向状态{q}")
# 如果q状态与p状态相连,则当前状态的后缀链接指向q状态
if self.st[p].length + 1 == self.st[q].length:
self.st[cur].link = q
logger.debug(f"状态{p}的长度比状态{q}少1,把当前状态{cur}的后缀链接指向状态{q}")
# 如果不相连则开一个新状态,长度为p状态的下一个状态,后缀链接与转移指向q
# 搜索状态p,若c转移为q,则指向新状态,并搜索后缀链接的状态重复指向新状态
# 直到状态转移不为q,跳出
else:
self.sz += 1
logger.debug(f"状态{p}的长度与状态{q}的长度不连续,新建状态{self.sz}")
self.st[self.sz] = State(self.st[p].length + 1, self.st[q].link, deepcopy(self.st[q].trans))
logger.debug(f"新状态{self.sz}的长度为状态{p}的长度加1")
while p > -1 and self.st[p].trans.get(c) == q:
logger.debug(f"状态{p}转移中{c}的转移是状态{q},把指向{q}的转移改为指向新状态{self.sz}")
self.st[p].trans[c] = self.sz
logger.debug(f"查找状态{p}的后缀链接...")
p = self.st[p].link
logger.debug(f"后缀链接为状态{p}")
# 把当前状态与q的后缀链接指向新状态
self.st[q].link = self.st[cur].link = self.sz
logger.debug(f"把状态{q}与当前状态{cur}的后缀链接指向新状态{self.sz}")
logger.debug(f"当前状态{cur}的长度为:{self.st[cur].length}")
logger.debug(f"当前状态{cur}的后缀链接为:{self.st[cur].link}")
logger.debug(f"当前状态{cur}的转移为:{self._dict2str(self.st[cur].trans)}")
logger.debug(f"当前状态{cur}建立完成")
logger.debug("\n")
# 状态索引占位
self.sz += 1
self.last = cur
self.samstr += c def __add__(self, addition):
new_sam = deepcopy(self)
if isinstance(addition, str):
for c in addition:
new_sam._extend(c)
elif isinstance(addition, Sam):
for c in addition.samstr:
new_sam._extend(c)
return new_sam def __call__(self, s):
for c in s:
self._extend(c) def __str__(self):
pts = ""
for k, w in self.st.items():
pts += f"状态{k}: 长度:{w.length} 后缀链接-->{w.link} 转移:{self._dict2str(w.trans)}\n"
return pts def __getitem__(self, key):
return self.st[key] if __name__ == "__main__": s1 = "aabbabd"
s2 = "rtrbWHWUKkkh"
sam1 = Sam(s1)
sam2 = Sam(s2) print(sam1) #加的时候不会改变原后缀自动机
sam3 = sam1+sam2
sam4 = sam1+s2 #调用则在原自动机上更新
sam1(s2)
- 调试的时候日志级别设为DEBUG就行了
- 有空的时候更新相应字符串处理的算法
后缀自动机的python实现的更多相关文章
- 用c++后缀自动机实现最大公共字符串算法,并封装成Python库
后缀自动机的C++代码转自https://e-maxx.ru/algo/suffix_automata,其余封装为自写. 在C++文件同级目录建立setup.py文件,代码如下: # !/usr/bi ...
- BZOJ 后缀自动机四·重复旋律7
后缀自动机四·重复旋律7 时间限制:15000ms 单点时限:3000ms 内存限制:512MB 描述 小Hi平时的一大兴趣爱好就是演奏钢琴.我们知道一段音乐旋律可以被表示为一段数构成的数列. 神奇的 ...
- 【Codeforces235C】Cyclical Quest 后缀自动机
C. Cyclical Quest time limit per test:3 seconds memory limit per test:512 megabytes input:standard i ...
- 【hihocoder#1413】Rikka with String 后缀自动机 + 差分
搞了一上午+接近一下午这个题,然后被屠了个稀烂,默默仰慕一晚上学会SAM的以及半天4道SAM的hxy大爷. 题目链接:http://hihocoder.com/problemset/problem/1 ...
- 【BZOJ-3998】弦论 后缀自动机
3998: [TJOI2015]弦论 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 2018 Solved: 662[Submit][Status] ...
- HDU 4622 Reincarnation (查询一段字符串的不同子串个数,后缀自动机)
Reincarnation Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 131072/65536 K (Java/Others)To ...
- hihoCoder 后缀自动机三·重复旋律6
后缀自动机三·重复旋律6 时间限制:15000ms 单点时限:3000ms 内存限制:512MB 描述 小Hi平时的一大兴趣爱好就是演奏钢琴.我们知道一个音乐旋律被表示为一段数构成的数列. 现在小Hi ...
- hihoCoder #1445 : 后缀自动机二·重复旋律5
#1445 : 后缀自动机二·重复旋律5 时间限制:10000ms 单点时限:2000ms 内存限制:256MB 描述 小Hi平时的一大兴趣爱好就是演奏钢琴.我们知道一个音乐旋律被表示为一段数构成的数 ...
- 数据结构:后缀自动机 WJMZBMR讲稿的整理和注释
链接放在这里,有点难理解,至少我个人是的. 后缀自动机是一种有限状态自动机,其功能是识别字符串是否是母串的后缀.它能解决的问题当然不仅仅是判断是不是后缀这种事,跟字符串的连续子串有关的问题都可以往这个 ...
随机推荐
- C# 导出 数据 到Excel
/// <summary> /// 实现将数据导出至Excel, /// 在上面的代码中,我们首先将gridview绑定到指定的数据源中,然后在button1的按钮(用来做导出到EXCEL ...
- 第十八章 Python批量管理主机(paramiko、fabric与pexpect)
这个人的文章不错:http://lizhenliang.blog.51cto.com/all/7876557 转载:http://lizhenliang.blog.51cto.com/7876557/ ...
- MFC中 自定义消息
想在对话框显示出来后立即执行一段代码. 方法之一是自定义消息,即添加一个自定义的消息在消息队列中等待对话框初始化之后从消息队列中读取消息执行代码. 在OnInitDialog返回之前post一个自定义 ...
- windows 控制台cmd乱码的解决办法
windows 控制台cmd乱码的解决办法 我本机的系统环境: OS Name: Microsoft Windows 10 企业版 OS Version: 10.0.14393 N/A Build 1 ...
- 改用MyAnalyzer的KMeans聚类算法
<strong><span style="font-size:18px;">/*** * @author YangXin * @info 改用MyAnaly ...
- Android 基于Retrofit+Rxjava搭建的简单易用的网络架构
装逼開始之前,为大家推荐两篇文章,用来更好的学习Retrofit和Rxjava. 在这里我们要感谢互联网装逼行业勇于献身,甘于奉献的的大婶们. 我仅代表个人,给您们跪舔了. Retrofit:Retr ...
- HTML字体对应word字体
42磅对应初号. 36磅对应小初. 26磅对应一号. 24磅对应小一号. 22磅对应二号. 18磅对应小二号. 16磅对应三号. 15磅对应小三号. 14磅对应四号. 12磅对应小四号. 10.5磅对 ...
- 解析iscroll-小demo
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name ...
- SQLAlchemy使用笔记--SQLAlchemy ORM(三)
參考: http://docs.sqlalchemy.org/en/rel_1_0/orm/tutorial.html#eager-loading 预先载入 前面的代码,由于是lazy load.当我 ...
- Allegro中解决鼠标放在走线上网络名、走线长度显示不出来的问题
一些PCB设计者在使用allegro时,由于一些误操作 导致当鼠标放在走线(cline)和网络(net)上面时,软件没有显示该走线的所属网络,或者相关的长度信息.本人经过help文档发现,以下方法可以 ...