字符串hash + 二分答案 - 求最长公共子串 --- poj 2774

Long Long Message

Problem‘s Link:http://poj.org/problem?id=2774



Mean:

求两个字符串的最长公共子串的长度。

analyse:

前面在学习后缀数组的时候已经做过一遍了,但是现在主攻字符串hash,再用字符串hash写一遍。

这题的思路是这样的:

1)取较短的串的长度作为high,然后二分答案(每次判断长度为mid=(low+high)>>1是否存在,如果存在就增加下界;不存在就缩小上界);

2)主要是对答案的判断(judge函数)。具体参看代码注释。

Time complexity:O(n)

Source code:

// Memory   Time
// 1347base     0MS
// by : Snarl_jsb
// 2014-10-04-21.16
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<string>
#include<climits>
#include<cmath>
#define ULL unsigned long long
using namespace std;

string s1,s2;
int l1,l2,seed=131;
vector<ULL> hash;
bool judge(int x)
{
    hash.clear();
    ULL tmp=0;
    for (int i = 0; i < x; i++)
    {
        tmp=tmp* seed + s1[i];
    }
    hash.push_back(tmp);
    ULL base =1;
    for (int i = 1; i < x; i++)
    {
        base *= seed;
    }
    for (int i = x; i < l1; i++)
    {
        tmp=(tmp*seed+s1[i])-base*s1[i-x]*seed;
        hash.push_back(tmp);
    }
    sort(hash.begin(),hash.end());
    ULL hashval = 0;
    for (int i = 0; i < x; i++)
    {
        hashval = hashval * seed + s2[i];
    }
    if (binary_search(hash.begin(),hash.end(),hashval))
        return 1;
    for (int i = x; i < l2; i++)
    {
        hashval = (hashval-(s2[i-x])*base)*seed+s2[i];
        if (binary_search(hash.begin(),hash.end(),hashval))
            return 1;
    }
    return 0;
}
int main()
{
    while (cin>>s1>>s2)
    {
        l1=s1.size();
        l2=s2.size();
        int ans = 0;
        int high = min(l1,l2);
        int low = 0;

        while (low <= high)
        {
            int mid = (low+high)>>1;
            if (judge(mid))
            {
                ans = mid;
                low = mid+1;
            }
            else
                high = mid-1;
        }
        printf("%d\n",ans);
    }
    return 0;
}

注释代码:

// Memory   Time
// 1347k     0MS
// by : Snarl_jsb
// 2014-10-04-21.16
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<string>
#include<climits>
#include<cmath>
#define ULL unsigned long long
using namespace std;

string s1,s2;
int l1,l2,seed=131;
vector<ULL> hash;
bool judge(int x)
{
    hash.clear();//多组数据时不要忘了清空全局数组
    //构造s1串的hash表
    ULL tmp=0;
    for (int i = 0; i < x; i++)
    {
        tmp=tmp* seed + s1[i];
    }
    hash.push_back(tmp);
    ULL base =1;
    for (int i = 1; i < x; i++)//求出到达x的base值
    {
        base *= seed;
    }
    for (int i = x; i < l1; i++)
    {
        tmp=(tmp*seed+s1[i])-base*s1[i-x]*seed;
        hash.push_back(tmp);
    }
    //构造完毕
    sort(hash.begin(),hash.end()); //二分查找加速,必需先排序
    ULL hashval = 0;
    for (int i = 0; i < x; i++)//求出s2串0到x的hash值
    {
        hashval = hashval * seed + s2[i];
    }
    if (binary_search(hash.begin(),hash.end(),hashval))//查找s2串0到x的hash值是否在s1串的hash表中
        return 1;
    for (int i = x; i < l2; i++)//如果上面的s2串0到x的hash值未匹配成功,这儿接着匹配s2串长度为x的hash值是否出现在s1串的hash表中
    {
        hashval = hashval*seed+s2[i]-s2[i-x]*base*seed;
        if (binary_search(hash.begin(),hash.end(),hashval))
            return 1;
    }
    return 0;
}
int main()
{
    while (cin>>s1>>s2)
    {
        l1=s1.size();
        l2=s2.size();
        int ans = 0;
        int low=0,high = min(l1,l2);
        while (low <= high)//二分答案
        {
            int mid = (low+high)>>1;
            if (judge(mid))//判断答案是否可行
            {
                ans = mid;
                low = mid+1;
            }
            else
                high = mid-1;
        }
        printf("%d\n",ans);
    }
    return 0;
}

  

时间: 2024-10-12 09:52:05

字符串hash + 二分答案 - 求最长公共子串 --- poj 2774的相关文章

POJ 2774 后缀数组:求最长公共子串

思路:其实很简单,就是两个字符串连接起来,中间用个特殊字符隔开,然后用后缀数组求最长公共前缀,然后不同在两个串中,并且最长的就是最长公共子串了. 注意的是:用第一个字符串来判断是不是在同一个字符中,刚开始用了第二个字符的长度来判断WA了2发才发现. #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<map> #include<

【华为OJ】【081-查找两个字符串a,b中的最长公共子串】

[华为OJ][算法总篇章] [华为OJ][081-查找两个字符串a,b中的最长公共子串] [工程下载] 题目描述 查找两个字符串a,b中的最长公共子串 输入描述 输入两个字符串 输出描述 返回重复出现的字符 输入例子 abcdefghijklmnop abcsafjklmnopqrstuvw 输出例子 jklmnop 算法实现 import java.util.Scanner; /** * Author: 王俊超 * Date: 2016-01-04 08:43 * Declaration: A

poj 2774 Long Long Message,后缀数组,求最长公共子串 hdu1403

题意:给出两个字符串,求最长公共子串的长度. 题解:首先将两个字符串连在一起,并在中间加一个特殊字符(字串中不存在的)分割,然后两个串的最长公共字串就变成了所有后缀的最长公共前缀.这时就要用到height数组,因为任意两个后缀的公共前缀必定是某些height值中的最小值,而这个值如果最大则一定是height中的最大值.在此题中还要注意height最大一定要在两个值所代表的后缀分属不同的字符串地前提下. #include<cstdio> #include<cstring> #incl

求最长公共子串(串)

题目描述 求采用顺序结构存储的串s和串t的一个最长公共子串,若没有则输出false,若最长的有多个则输出最先出现的那一串. 输入要求 输入两个字符串 输出要求 输出公共子串 假如输入 abcdef adbcef 应当输出 bc 思路: 1. 将连个字符串分别以行列组成一个矩阵. 2.若该矩阵的节点对应的字符相同,则该节点值为1. 3.当前字符相同节点的值 = 左上角(d[i-1, j-1])的值 +1,这样当前节点的值就是最大公用子串的长. (s2) b c d e (s1) a        

HDU 1403 Longest Common Substring(后缀数组啊 求最长公共子串 模板题)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1403 Problem Description Given two strings, you have to tell the length of the Longest Common Substring of them. For example: str1 = banana str2 = cianaic So the Longest Common Substring is "ana", a

求最长公共子串 Longest Common Subsequence

最长公共子串 // Longest Common Subsequence 子串有别于子序列, 子串是连续的, 而子序列可以不连续 /*----------------------------------------------------对给定的字符串,本题要求你输出最长对称子串的长度.例如,给定"Is PAT&TAP symmetric?",最长对称子串为"s PAT&TAP s",于是你应该输出11.输入格式:输入在一行中给出长度不超过1000的

java求最长公共子串的长度

1这道题目就是给定两个字符串,然后求这两个字符串的最长公共子串的最大长度,假设我的f()方法是来求两个字符串的最大公共子串,从头开始逐一比较,如果相等,则 继续调用这个方法,使得递归的长度+1,如果不相等,则只要比较s1截掉一个和s2比较,和s2截掉和s1比较,两个中的最大者,如果s1或者s2中有一个长度为0,则最大公共长度就是0,return 2.代码示例: package zzl; public class 最长公共子串 { public static void main(String[]

求最长公共子串

poj2774,codevs3160 题目描述 Description 给出两个由小写字母组成的字符串,求它们的最长公共子串的长度. 输入描述 Input Description 读入两个字符串 输出描述 Output Description 输出最长公共子串的长度 样例输入 Sample Input yeshowmuchiloveyoumydearmotherreallyicannotbelieveityeaphowmuchiloveyoumydearmother 样例输出 Sample Ou

利用后缀数组(suffix array)求最长公共子串(longest common substring)

摘要:本文讨论了最长公共子串的的相关算法的时间复杂度,然后在后缀数组的基础上提出了一个时间复杂度为o(n^2*logn),空间复杂度为o(n)的算法.该算法虽然不及动态规划和后缀树算法的复杂度低,但其重要的优势在于可以编码简单,代码易于理解,适合快速实现. 首先,来说明一下,LCS通常指的是公共最长子序列(Longest Common Subsequence,名称来源参见<算法导论>原书第3版p223),而不是公共最长子串(也称为最长公共子串). 最长公共子串问题是在文本串.模式串中寻找共有的