字符串算法

KMP

\831. KMP字符串

https://www.acwing.com/problem/content/833/

请添加图片描述

def get_ne(s):
    ne = [0]*len(s)
    j = 0
    for i in range(2,N+1):
        while j and s[i]!=s[j+1]:
            j = ne[j]
        if s[i]==s[j+1]:
            j += 1
        ne[i] = j
    return ne
N = int(input())
s = [0]+list(input())
M = int(input())
p = [0]+list(input())

ne = get_ne(s)
print(ne)
res = []
j = 0
for i in range(1,M+1):
    while j>0 and s[j+1]!=p[i]:
        j = ne[j]
    if p[i]==s[j+1]:
        j += 1
    if j == N:
        res.append(i-N)
        j = ne[j]
print(*res)

Trie

\835. Trie字符串统计

https://www.acwing.com/problem/content/837/

请添加图片描述

N = int(input())
idx = 0
trie = [[0]*(26) for i in range(100010)]
cnt = [0 for i in range(100010)]
def insert(s):
    global idx
    net = 0
    for e in s:
        if not trie[net][ord(e)-97]:
            idx += 1
            trie[net][ord(e)-97] = idx
        net = trie[net][ord(e)-97]
    cnt[net] += 1
    
def query(s):
    net = 0
    for e in s:
        if not trie[net][ord(e)-97]:
            return 0
        net = trie[net][ord(e)-97]
    return cnt[net]
    
for i in range(N):
    Q,x = input().split()
    if Q=='I':
        insert(x)
    elif Q=='Q':
        print(query(x))

\143. 最大异或对

https://www.acwing.com/problem/content/145/

请添加图片描述

N = int(input())
lis = list(map(int,input().split()))
trie = [[0,0] for i in range(N*31)]
idx = 0

def insert(x):
    global idx
    net = 0
    for i in range(31,-1,-1):
        u = x>>i&1
        if not trie[net][u]:
            idx += 1
            trie[net][u] = idx
        net = trie[net][u]

# 选最大的异或对
def query(x):
    net = 0
    res = 0
    for i in range(31,-1,-1):
        u = x >> i & 1
        if trie[net][not u]:
            res = res*2+1
            net = trie[net][not u]
        else:
            res = res*2+0
            net = trie[net][u]
    return res

for li in lis:
    insert(li)
max_n = 0
for li in lis:
    max_n = max(max_n,query(li))
print(max_n)

AC自动机

\1282. 搜索关键词

https://www.acwing.com/problem/content/1284/

请添加图片描述

from collections import deque

def insert(s):
    global idx
    t = 0
    for c in s:
        if not trie[t][ord(c)-97]:
            idx += 1
            trie[t][ord(c)-97] = idx
        t = trie[t][ord(c)-97]
    cnt[t] += 1
def build():
    dq = deque()
    for i in range(26):
        if trie[0][i]:
            dq.append(trie[0][i])
    while dq:
        t = dq.popleft()
        for i in range(26):
            c = trie[t][i]
            if not c:
                trie[t][i] = trie[ne[t]][i]
            else:
                ne[c] = trie[ne[t]][i]
                dq.append(c)


T = int(input())
for _ in range(T):
    n = int(input())
    strs = []
    for i in range(n):
        strs.append(input())
    pages = input().strip()
    trie = [[0] * 26 for i in range(50 * n + 10)]
    idx = 0
    cnt = [0] * (50 * n + 10)

    # 构建字典树
    for s in strs:
        insert(s)
    # 构建next数组
    ne = [0 for i in range(50 * n + 10)]
    build()
    # print(ne)
    res = 0
    j = 0
    for i in range(len(pages)):
        t = ord(pages[i]) - 97
        j = trie[j][t]
        p = j
        while p:
            # print(res)
            res += cnt[p]
            cnt[p] = 0
            p = ne[p]

    print(res)

\1285. 单词(ac自动机+拓扑排序)

https://www.acwing.com/problem/content/1287/

请添加图片描述

from collections import deque

def insert(s):
    global idx
    t = 0
    for c in s:
        if not trie[t][ord(c)-97]:
            idx += 1
            trie[t][ord(c)-97] = idx
        t = trie[t][ord(c)-97]
        # 走到这个点的路径数
        cnt[t] += 1
    idx_word.append(t)
    

def build():
    dq = deque()
    for i in range(26):
        if trie[0][i]:
            top_sort_lis.append(trie[0][i])
            dq.append(trie[0][i])
    while dq:
        t = dq.popleft()
        for i in range(26):
            c = trie[t][i]
            if not c:
                trie[t][i] = trie[ne[t]][i]
            else:
                ne[c] = trie[ne[t]][i]
                top_sort_lis.append(c)
                dq.append(c)


n = int(input())
trie = [[0]*26 for i in range(1000010)]
idx = 0
cnt = [0 for i in range(1000010)]
ne = [0 for i in range(1000010)]
idx_word = []
# 记录BFS添加的顺序,用于拓扑排序
top_sort_lis = []
for i in range(n):
    insert(input())
    
build()

for i in range(idx-1,-1,-1):
    cnt[ne[top_sort_lis[i]]] += cnt[top_sort_lis[i]]
        
for i in range(n):
    print(cnt[idx_word[i]])

\1. 奇怪的编程

https://www.lanqiao.cn/problems/4270/learning/?page=1&first_category_id=1&name=%E5%A5%87%E6%80%AA%E7%9A%84%E7%BC%96%E7%A8%8B

请添加图片描述

from collections import deque

# 构建trie
def insert(s):
  global idx,longest
  u = 0
  for c in s:
    if not trie[u][ord(c)-97]:
      idx += 1
      trie[u][ord(c)-97] = idx
    u = trie[u][ord(c)-97]
  cnt[u] = 1
  cnt_length[u] = len(s)
  longest = max(longest,len(s))

# 构建ac自动机next数组
def get_ne():
  dq = deque()
  for i in range(26):
    if trie[0][i]:
      dq.append(trie[0][i])
  while dq:
    u = dq.popleft()
    for i in range(26):
      c = trie[u][i]
      if not c:
        trie[u][i] = trie[ne[u]][i]
      else:
        ne[c] = trie[ne[u]][i]
        dq.append(c)

n,k = map(int,input().split())
trie = [[0]*26 for i in range(450)]
idx = 0
ne = [0 for i in range(450)]
# 以当前节点字母结尾的有一个单词
cnt = [0 for i in range(450)]
# 以当前节点字母结尾的单词的长度
cnt_length = [0 for i in range(450)]
# 保存所有编码集D中最长的
longest = 0
for i in range(n):
  insert(input())
get_ne()
res = []
for _ in range(k):
  ipt = input()
  j = 0
  # 表示到第i的位置是否能匹配到单词
  dp = [0]*(10010)
  dp[0] = 1
  last = 0
  for i in range(len(ipt)):
    j = trie[j][ord(ipt[i])-97]
    p = j
    while p:
      # 如果当前位置能匹配到一个单词则更新last
      if cnt[p] and dp[i+1-cnt_length[p]]:
        dp[i+1] = 1
        last = i+1
        break
      p = ne[p]
    if last + longest < i+1:
      break
  res.append(last)
# print(ne)
print(*res,sep='\n')
  • 6
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值