后缀自动机的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讲稿的整理和注释
链接放在这里,有点难理解,至少我个人是的. 后缀自动机是一种有限状态自动机,其功能是识别字符串是否是母串的后缀.它能解决的问题当然不仅仅是判断是不是后缀这种事,跟字符串的连续子串有关的问题都可以往这个 ...
随机推荐
- 多线程一共就俩问题:1.线程安全(访问共享数据) 2.线程通信(wait(),notify())
多线程一共就俩问题:1.线程安全(访问共享数据) 2.线程通信(wait(),notify()) 1.线程安全,无非就是加锁,访问共享资源时,synchronized 2.线程通信,就是控制各个线程之 ...
- Mac测试模拟慢网速
先普及一下Kb,KB,Kbps,Mb,Mbps等一些列概念 1Byte = 8bit 1KB (Kilobyte 千字节)=1024Byte 1MB (Megabyte,兆字节,简称“兆”)=1024 ...
- 【转】.net 经典面试题
[转].net 经典面试题 1. 简述 private. protected. public. internal 修饰符的访问权限. 答 . private : 私有成员, 在类的内部才可以访问. ...
- 说说GestureDetector.OnGestureListener onScroll函数
public abstract boolean onScroll (MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) ...
- 前台页面获取servlet传过来的数据
servlet中的代码: public void doGet(HttpServletRequest request, HttpServletResponse response) throws Serv ...
- windows 网络编程[转]
利用winsock编写网络应用程序服务端的步骤简述如下WSAStartup 初始化网络编程库 socket 创建套接字 bind 指定地址.端口,绑定套接字 listen 进入监听状态 accept ...
- 2016.6.21 maven:Failure to transfer ... from ....
问题描述: 才刚新建的工程,什么都没做,就显示pom.xml有问题,在第一行的标签上 有如下错误: 点击详情: Failure to transfer org.apache.maven:maven-p ...
- DexClassLoader和PathClassLoader载入Dex流程
0x00 在上一篇文章apk安装和优化原理,在最后我们分析了DexClassLoader和PathClassLoader的构造函数的不同. PathClassLoader最后调用的是new DexFi ...
- jquery代码小片段
1. 使用jQuery来切换样式表 //找出你希望切换的媒体类型(media-type),然后把href设置成新的样式表. $(‘link[media="screen"]‘).at ...
- link标签的rel属性
<link>标签定义了当前文档与 Web 集合中其他文档的关系.link 元素是一个空元素,它仅包含属性.此元素只能存在于 head 部分,不过它可出现任何次数.在 HTML 中,< ...