zoukankan      html  css  js  c++  java
  • 扩展KMP(Z函数)

    给定一个串 (A) 和一个串 (B)。问 (B) 的所有后缀和 (A)(lcp)

    (1 le |A|,|B| le 10^7)

    首先考虑解决一个简单一点的问题:当 (A=B) 的时候的答案。

    与 KMP 类似,我们需要求一个数组 (nxt(i)),表示 ((A...|A|))(A)(lcp)

    与 manacher 类似,我们考虑尽可能地利用之前求出的信息。

    我们维护最靠右的匹配段 (l...r),那么 (i...|A|)(A) 的匹配的前半部分就相当于 (1...i-l+1)(A) 的匹配。如果成功匹配上了,那么还可以继续匹配。

    模拟实现即可。势能分析可得复杂度为 (O(|A|))

    现在我们有了 (A)(nxt) 数组,我们尝试解决最开始那个问题。这回我们扫 (B),同样维护一个最靠右的匹配段 (l...r),那么 (i...|B|)(A) 的匹配的前半部分就相当于 (A)(1...i-l+1)(A) 的匹配。如果成功匹配上了,那么还可以继续匹配。

    复杂度:(O(|A| + |B|))

    常见应用

    • 找一个前缀最多在前面连续循环出现多少次。(KMP是判断一个前缀是否循环以及最小循环节)
    • 解决一些中间子串与前缀的匹配问题。

    例题

    Password

    Prefixes and Suffixes

    字符串匹配

    模板(调试用)

    next[1] = n;
    for (int i = 2, l = 1, r = 1; i <= n; ++i) {
    	int tar = i - l  + 1, mx = max(0, r - i + 1);
    	next[i] = min(next[tar], mx);
    	while (i + next[i] <= n && s[i + next[i]] == s[next[i] + 1]) ++next[i];
    	if (i + next[i] - 1 > r)	r = i + next[i] - 1, l = i;
    }
    int m = strlen(t + 1);
    for (int i = 1, l = 0, r = 0; i <= m; ++i) {
    	int tar = i - l + 1, mx = max(0, r - i + 1);//bug
    	ans[i] = min(next[tar], mx);
    	while (i + ans[i] <= m && t[i + ans[i]] == s[ans[i] + 1])	++ans[i];
    	if (i + ans[i] - 1 > r)	r = i + ans[i] - 1, l = i;
    }
    
  • 相关阅读:
    Windows下不能启动mysql服务错误总结
    使用NSOperationQueue简化多线程开发(转)
    “四人帮”的设计模式经得起时间的考验么?(转)
    ObjectiveC category
    svn add 输出 A (bin) (转)
    NSNotification学习笔记
    浅析UITableViewCell的工作机制
    关于git分支的使用
    delegate使用方法之assign
    ARC(Automatic Reference Counting )技术概述(转)
  • 原文地址:https://www.cnblogs.com/JiaZP/p/14122535.html
Copyright © 2011-2022 走看看