字符串匹配(hash算法)

hash函數對你們來講不陌生吧 ?php

而此次咱們就用hash函數來實現字符串匹配。函數

首先咱們會想一下二進制數。spa

對於任意一個二進制數,咱們將它化爲10進制的數的方法以下(以二進制數1101101爲例):翻譯

hash用的也是同樣的原理,爲每個前綴(也能夠後綴,筆者習慣1 base,因此喜歡用前綴來計算,Hash[i] = Hash[i - 1] * x + s[i](其中1 < i <= n,Hash[0] = 0)。blog

 

通常地,字符串

 

而對於l - r區間的hash值,則爲:get

 

可是若是n很大呢?那樣不是會溢出了嗎?string

所以咱們把hash值儲存在unsigned long long裏面, 那樣溢出時,會自動取餘2的64次方,but這樣可能會使2個不一樣串的哈希值相同,但這樣的機率極低(不排除你的運氣很差)。hash

所以咱們能夠經過Hash值來比較兩個字符串是否相等。it

給出多項式hash的處理:

 

typedef unsigned long long ull;
const int N = 100000 + 5;
const ull base = 163;
char s[N];
ull hash[N];

void init(){//處理hash值
    p[0] = 1;
    hash[0] = 0;
    int n = strlen(s + 1);
   for(int i = 1; i <=100000; i ++)p[i] =p[i-1] * base;
   for(int i = 1; i <= n; i ++)hash[i] = hash[i - 1] * base + (s[i] - 'a');
}

ull get(int l, int r, ull g[]){//取出g裏l - r裏面的字符串的hash值
    return g[r] - g[l - 1] * p[r - l + 1];
}

 

咱們來看到題目吧:傳送門

題目大意:

是有一份文件,前面是密文,後面是原文,但那我的接到這個文件後不知道中間從哪裏開始是原文,因此你要幫忙還原一下,若是後面原文比密文少,你就將它補全, 第一行是密文轉換格式,例如第二個樣例表示將q翻譯成a,w翻譯成b。

思路:

咱們只要先把密文都翻譯成明文,而後去比較原來的字符串的後綴和翻譯以後的字符串前綴的最長匹配長度就行(注:最長匹配的長度不能超過原長的一半)

hash水題(附AC代碼):

 

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef unsigned long long ull;
const int N = 100000 + 5;
const ull base = 163;
ull Hash1[N], Hash2[N], p[N];

char s[N], t[30], r[N];

int T;

int c[30];

void init(){
    p[0] = 1;
   for(int i = 1; i <=100000; i ++)p[i] =p[i-1] * base;
}

ull get(int l, int r, ull g[]){
    return g[r] - g[l - 1]*p[r - l + 1];
}

void work(){
    for(int i = 0; i < 26; i ++) c[t[i] - 'a'] = i;
    //puts(r+1);
    int n = strlen(s + 1);
    Hash1[0] = Hash2[0] = 0;
    for(int i = 1; i <= n; i ++){
        Hash1[i] = Hash1[i - 1] * base + (s[i] - 'a');
        Hash2[i] = Hash2[i - 1] * base + (c[s[i] - 'a']);
    }
    int ans = n;
    for(int i = n; i < n * 2; i ++){
        if(i & 1) continue;
        int tmp = i / 2;
        int len =n - tmp;
        ull s1 = get(1, len, Hash2);
        ull s2 = get(n - len + 1, n, Hash1);
        if(s1 == s2){
            ans = tmp;
            break;
        }
        //printf("%llu %llu\n", s1, s2);
    }
    //printf("ans = %d\n", ans);
    for(int i = 1; i <= ans; i ++)printf("%c", s[i]);
    for(int i = 1; i <= ans; i ++)printf("%c", c[s[i]-'a'] + 'a');
    puts("");
}

int main(){
    scanf("%d", &T);
    init();
    while(T--){
        scanf("%s%s", t, s + 1);
        work();
    }
    return 0;
}
相關文章
相關標籤/搜索