1. 程式人生 > 實用技巧 >字串(hash演算法完成)

字串(hash演算法完成)

字串(hash演算法完成)

題目描述

  給一個字串T,問在字串T 中可以包含最多多少個不重疊的字串S。
  字串中的每個字元為小寫或者大寫字母。

輸入

  第一行輸入一個字串S。
  第二行輸入一個字串T。

輸出

  輸出一行,包括一個整數表示答案。

樣例輸入

aba
abababa

樣例輸出

2

提示

【資料範圍】:
  20%的資料,1<=字串T 長度<=20000, 1<=字串S 長度<=100;
  100%的資料,1<=字串T 長度<=1000000, 1<=字串S 長度<=100000。

題目思路

  初看題目,發現可以用暴力,就是可以先用find函式找子串,再用erase刪除(不懂出門左轉找度娘),但只能騙20%分數,find函式用O(n),earse函式也要用O(n),暴力分分鐘TLE。那如何解決,這裡就採用了hash演算法,求子串的hash值,再進行匹配,匹配成功的記錄,然後輸出

原始碼

#include<bits/stdc++.h> //萬能頭,不多加解釋
using namespace std;
string s,st;
const long long p=29,mod1=1e9+7,mod2=1e9+9;//提醒:這裡p,mod1最好用質數,否則在轉換hash值時可能會因為出現公因數而轉換失誤,mod1要開大一點,否則也會容易翻車
long long hash1[1000007],sh,l,pow1=1,sum=0,ha1,ha2,hash2[1000009];//pow1記得1,否則平方時有可能爆0
void hs()
{   
    long long l=s.size();
    for(int i=0;i<s.size();i++)
       sh=(sh*p%mod1+s[i]%mod1)%mod1;//用字首和和進位制轉換來轉換子串hash
    for(int i=1;i<=st.size();i++)
    {
        hash1[i]=(hash1[i-1]*p%mod1+st[i-1])%mod1;
        hash2[i]=(hash2[i-1]*p%mod2+st[i-1])%mod2;//同上,求長串hash
    }
    for(int i=1;i<=l;i++) 
       pow1=pow1*p%mod1;//求平方,可以轉換為((pow1%mod1)*p)%mod1或((pow1%mod1)*(p%mod1))%mod1,這2個不容易TLE,pow也勉強,但容易TLE
    for(int i=l;i<=st.size();)
    {
       ha1=(hash1[i]-(hash1[i-l]*pow1)%mod1+mod1)%mod1;
       ha2=(hash2[i]-(hash2[i-l]*pow1)%mod2+mod2)%mod2;//當前這一長串的子串的子串字首和
       if(ha1==sh && ha2==sh)
       {
        i+=l;//跳過這一子串,否則會造成重複
        sum++;
       }
       else i++;
    }
}
int main() 
{
    getline(cin,s);
    getline(cin,st);//cin也可
    hs();
    cout<<sum;
    return 0;//完結撒花
}

碼後反思

  這題也算是一個小毒瘤了,首先在判斷子串是否相符的那一處for的範圍卡了很久,但也沒有拿滿,發現原來就只是mod1定義太小,容易重複。

擴充套件

  如果覺得看懂了,出門右轉
  題目與這題很像,但很多坑