实现哈希表+二进制搜索

时间:2015-05-21 07:50:12

标签: c++ hash hashtable binary-search string-matching

这是有问题的问题:http://www.codechef.com/problems/SSTORY [竞争规划]

TLDR:给定两个字符串,找到最大的公共子字符串。

我想我可以在改变(通过BS)匹配长度上使用Rabin-Karp算法。因此,我为length=current_B上的每个子字符串创建了一个哈希(它将采用O(len(S1)))并将其与S2 O(len(S2))的每个子字符串进行匹配。由于约束条件为2.5 * 10 ^ 5,因此应该可以在2秒的时间限制内轻松运行。

我的第一种方法是使用双重散列(以减少碰撞):

(查看最后一个,因为那是最新的;这可能没有上面那个错误。)

  

http://www.codechef.com/viewsolution/6986274

     

http://www.codechef.com/viewsolution/6986284

     

http://www.codechef.com/viewsolution/6986295

     

http://www.codechef.com/viewsolution/6986342

然而,所有返回的TLE。

我在这里阅读(http://apps.topcoder.com/forums/wiki/x/aoE_/?module=Thread&threadID=826779&mc=7&view=tree),TLE的原因可能是将成对推入一组(显然可能代价高昂)。用户建议使用链接列表(我从http://www.algolist.net/Data_structures/Hash_table/Chaining获得)。

我使用链接列表重新实现了相同的算法并提交了:

#include <cstdio>
#include <string>
#include <iostream>
#include <cstring>

using namespace std;

#define MOD 1000000007
#define HVAL 23

class LinkedHashEntry {
    private:
        int key;
        string value;
        LinkedHashEntry *next;

    public:
        LinkedHashEntry(int key, string value) 
        {
            this->key = key;
            this->value = value;
            this->next = NULL;
        }

        int getKey() 
        {
            return key;
        }

        string getValue() 
        {
            return value;
        }

        void setValue(string value) 
        {
            this->value = value;
        }

        LinkedHashEntry *getNext()
        {
            return next;
        }

        void setNext(LinkedHashEntry *next)
        {
            this->next = next;
        }
};

#define TABLE_SIZE 128

class HashMap
{
    private:
        LinkedHashEntry **table;

    public:
        HashMap() 
        {
            table = new LinkedHashEntry*[TABLE_SIZE];
            for (int i = 0; i < TABLE_SIZE; i++)
                table[i] = NULL;
        }

        int get(int key) 
        {
            int hash = (key % TABLE_SIZE);
            if (table[hash] == NULL)
                return 0;
            else 
            {
                LinkedHashEntry *entry = table[hash];
                while (entry != NULL && entry->getKey() != key)
                    entry = entry->getNext();
                if (entry == NULL)
                    return 0;
                else
                    return 1;
            }
        }

        void put(int key, string value) 
        {
            int hash = (key % TABLE_SIZE);
            if (table[hash] == NULL)
                table[hash] = new LinkedHashEntry(key, value);
            else 
            {
                LinkedHashEntry *entry = table[hash];
                while (entry->getNext() != NULL)
                    entry = entry->getNext();
                if (entry->getKey() == key)
                    entry->setValue(value);
                else
                    entry->setNext(new LinkedHashEntry(key, value));
            }
        }

        void remove(int key) 
        {
            int hash = (key % TABLE_SIZE);
            if (table[hash] != NULL) 
            {
                LinkedHashEntry *prevEntry = NULL;
                LinkedHashEntry *entry = table[hash];
                while (entry->getNext() != NULL && entry->getKey() != key) 
                {
                    prevEntry = entry;
                    entry = entry->getNext();
                }
                if (entry->getKey() == key) 
                {
                    if (prevEntry == NULL) 
                    {
                         LinkedHashEntry *nextEntry = entry->getNext();
                         delete entry;
                         table[hash] = nextEntry;
                    } 
                    else 
                    {
                         LinkedHashEntry *next = entry->getNext();
                        delete entry;
                         prevEntry->setNext(next);
                    }
                }
            }
        }

        ~HashMap()
        {
            for (int i = 0; i < TABLE_SIZE; i++)
            {
                if (table[i] != NULL) 
                {
                    LinkedHashEntry *prevEntry = NULL;
                    LinkedHashEntry *entry = table[i];
                    while (entry != NULL) 
                    {
                         prevEntry = entry;
                         entry = entry->getNext();
                         delete prevEntry;
                    }
                }
            }
            delete[] table;
        }
};

#define DEBUG 0

int h[250009];
int cnt;
int pt[250009];
string s, b;

inline int mod(int x, int y=MOD)
{
    return (x%y+y)%y;
}

void hash(string s)
{
    if(s.length()==0)
    {
        h[cnt]=0;
        return;
    }
    if(s.length()==1)
    {
        h[cnt]=s.at(0);
        return;
    }
    char x=s.at(0), y=s.at(s.length()-1);
    if(DEBUG) cout << "x=" << x << "; y=" << y << "; ";
    if(cnt)
    {
        if(DEBUG) printf("h[cnt]=%d; ", h[cnt]);
        if(DEBUG) printf("h[cnt-1]=%d; ", h[cnt-1]);
        h[cnt]=mod(h[cnt-1]-mod((x-'a'+1)*pt[s.length()-2]))*HVAL+y-'a'+1;
        h[cnt]=mod(h[cnt]);
    }
    else
    {
        h[cnt]=0;
        for(int i=0; i<s.length(); i++)
        {
            h[cnt]*=HVAL;
            h[cnt]=mod(h[cnt], MOD);
            h[cnt]+=s.at(i)-'a'+1;
            h[cnt]=mod(h[cnt], MOD);
        }
    }
}

int main()
{
    if(DEBUG) freopen("SSTORY.in", "r", stdin);
    HashMap hashes;
    cin >> b >> s;
    int ls=s.length(), lb=b.length();
    int low=0, high=ls+1, mid=(low+high)/2;
    int ans, ansLen=0, minI=lb+2;

    pt[0]=1;
    for(int i=1; i<=lb; i++)
    {
        pt[i]=pt[i-1]*HVAL;
        pt[i]=mod(pt[i], MOD);
    }

    while(low<high)
    {
        memset(h, 0, sizeof(h));
        int ol=low, oh=high, om=mid;
        int flag=0;
        cnt=0;
        for(int i=0; i+mid<=lb; i++)
        {
            if(DEBUG) printf("hash(b.substr(%d, %d))=", i-(i>0), mid+(i>0));
            hash(b.substr(i-(i>0), mid+(i>0)));
            if(DEBUG) cout << "hash(" << b.substr(i-(i>0), mid+(i>0)) << ")=" << h[cnt] << endl;
            hashes.put(h[cnt], b.substr(i-(i>0), mid+(i>0)));
            cnt++;
        }
        cnt=0;
        for(int i=0; i+mid<=ls; i++)
        {
            hash(s.substr(i-(i>0), mid+(i>0)));
            if(DEBUG) printf("Checking ");
            if(DEBUG) printf("hash(s.substr(%d, %d))=", i-(i>0), mid+(i>0));
            if(DEBUG) cout << "hash(" << s.substr(i-(i>0), mid+(i>0)) << ")=" << h[cnt] << endl;
            if(hashes.get(h[cnt]) && mid!=0 && (minI>ans || ansLen<mid)) 
            {
                if(DEBUG) cout << "^ WORKING" << endl;
                ans=minI=i;
                ansLen=mid;
                flag=1;
            }
            cnt++;
        }
        if(flag)
            low=mid;
        else
            high=mid;
        mid=(low+high)/2;
        if(low==ol && high==oh && mid==om)
            break;
    }

    if(ansLen<=0)
        printf("0\n");
    else
    {
        cout << s.substr(ans, ansLen);
        printf("\n%d\n", ansLen);
    }

    return 0;
}

两者都导致SIGABRT(可能是某些访问,例如s.at(-1)或其他)。

你能在我的代码中找到错误吗?我已经解决了这个问题3天了:/谢谢:)

0 个答案:

没有答案