哈希表入门题目总结(HDU 1280、1425、2027、3833、1496、2648 POJ 1200)

今天做了一天的哈希表题目,虽然不是哈希算法,但是感觉先把这哈希表搞定了,再学哈希算法的时候会快一些,所以今天搞得现在都有点头痛了,看了一天的电脑……

快要睡觉了,整理一下今天的成果。整理一下题目与思想,明天学哈希算法的时候应该会有些帮助。

先推荐一个哈希入门网站,还没做题之前,我把这网站关于哈希的都看了个遍,有些明白了才开始做题的:http://wenku.baidu.com/view/98383d34f111f18583d05a81.html

总的来说,在很多数据面前,如果要处理,我们自然会想到用数组,链表,或者线段树去处理,当然,这些不失为一种好的解决办法。不过数组寻址容易,插入和删除困难,而且如果n太大,遍历会超时;链表插入删除容易,但是遍历很慢;线段树结构复杂,在很多数组面前,处理和遍历也很烦,有时也是会超时的。所以人们就想到了这个哈希算法解决这个问题。

由上面的解释大概也明白了哈希是怎么做出来的了。就是把那些数据给上地址,结合链表的特点,就能做到寻址又快,插入删除查询又快的方法了。不过这里说太多了,这应该是哈希算法的时候才会用得到的。哈希表几乎都是和地址有关的,把地址给搞定了,题目就做得很简单了,时间也会少很少了。

其实哈希就像字典一样,把那些地址都给确定好了,然后查找的时候就快了。看上面给出的那个网站,里面有更详细的解释……

做哈希的原因:这段时间做题发现自己对数据处理很弱,在数据很多的情况下,总是会超时……而哈希在这方面出类拔萃,不得不学了!

第一道练习题:HDU 1280 前m大的数

#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#define mem(a,b) memset(a,b,sizeof(a))  
#define M 1000005  
typedef long long ll;  
using namespace std;  
int a[3005],b[10005];  
int main()  
{  
    int n,m,i,j;  
    while(cin>>n>>m)  
    {  
        mem(b,0);  
        int k=0;  
        for(i=0; i>a[i];  
        for(i=0; i0&&m>0;)  
        {  
            if(!b[i]) {i--;continue;}  
            if(k) cout<<' '<

第二题 HDU 1425 sort

#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#define mem(a,b) memset(a,b,sizeof(a))  
typedef long long ll;  
using namespace std;  
#define M 500000  
int hash[M*2+1];  
int main()  
{  
    int n,m;  
    while(cin>>n>>m)  
    {  
        int a,i,j,k=0;  
        mem(b,0);  
        for(i=0; i=0&&m>0; i--)  
        {  
            if(!hash[i]) continue;  
            if(k) cout<<' '<

第三题:HDU 2027 统计元音

#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#define mem(a,b) memset(a,b,sizeof(a))  
typedef long long ll;  
using namespace std;  
#define M 100005  
char s[101],hash[6]={'a','e','i','o','u'};  
int main()  
{  
    int t;  
    cin>>t;  
    getchar();  
    while(t--)  
    {  
        int i,a[200]={0};  
        gets(s);  
        for(i=0;i

第四题:HDU 3833 YY's new problem

思路:这题实在是苦死我了,刚开始看题目不知道怎么意思。有点让人产生歧义。又看了别人的解释,自己还是没明白什么意思,看得自己都困了睡了一下起来……发现就是给出一组数,如果有有 a-b=b-c 的话就是Y,否则是N。当然a 的位置在b 的前面,c 的位置在b 的后面。这样就明白了。唉……读题好慢……题目给出那个permutation,让自己产生歧义理解了好久。

不过这题当然用哈希就快了,如果用平常的方法的话,那就是3个for循环才能搞定了,虽然能搞定,但是n<=10000,这也会超时……因为题目的重要的字眼是位置,他们的位置是a,b,c 。而哈希的优势正好在于处理位置地址方面无与伦比,那这题用哈希做的话,当然是最好的解法。那要具体怎么做呢??……

比如一组数列:6 3 2 5 4 1 (题目给出的数是不会重复的)设输入的数为s。

输入的数直接做为hash数组的下标,数组等于1,表明这个数出现过。即hash[6]=1,然后由题目的条件,即6为b,则要找出a在不在前面出现过,如果出现过的话,那这个数列的后面肯定还有一个数c 符合a-b=b-c,转换一下就是2*b=a+c。就是小学的这个公式。现在问题来了,要怎么查找a最快呢,能不能直接一个判断就可以了呢??哈希说当然可以……

if(hash[s-j]+hash[s+j]==1)   就有了这个式子。例如输入6的时候判断一下j=1->s-1(j从1到s-1)。如果s-j出现过,那么s+j也会在s后面出现的,就是Y了;如果s+j出现过,那么s-j也会在s后面出现的,也是Y了;如果都没有出现过,那j 自增再判断……

比如当输入s=2 时,j=1->s-1,j=1时,s+j==3出现过,且s-j==1没出现过,这就正好符合了。2*2==3+1 正好是题目给出的式子的条件。s就是其中位数而已,如此判断岂不快唉……

#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#define mem(a,b) memset(a,b,sizeof(a))  
typedef long long ll;  
using namespace std;  
#define M 100005  
int hash[10003];  
int main()  
{  
    int t;  
    scanf("%d",&t);  
    while (t--)  
    {  
        int n,flag=0,i,j,s;  
        mem(hash,0);  
        scanf("%d",&n);  
        for (i = 1; i <= n; i++)  
        {  
            scanf("%d",&s);  
            hash[s]=1;  
            if (flag == 0)  
            {  
                for(j=1;j

第五题:HDU 1496  Equations

题意:就是给出a,b,c,d然后求出x1,x2,x3,x4有多少组解……

思路:这题还是收获很大啊……以前真不敢这么想,也不敢这么用过数组……哈希的思想太猛了!!

#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#define mem(a,b) memset(a,b,sizeof(a))  
typedef long long ll;  
using namespace std;  
#define M 2000000  
int s[101],hash[M+3];  
int main()  
{  
    int a,b,c,d,i,j,sum;  
    for(i=1;i<101;i++)  
        s[i]=i*i;  
    while(cin>>a>>b>>c>>d)  
    {  
        if(a>0&&b>0&&c>0&&d>0||a<0&&b<0&&c<0&&d<0)  //因为x那项永远是正数,如果系数都为正或者为负的时候明显不等于0  
        {  
            printf("0\n");  
            continue;  
        }  
        mem(hash,0);  
        sum=0;  
        for(i=1;i<101;i++)  
            for(j=1;j<101;j++)                //也可以先求前1项或者前3的,但是3个循环肯定比2个的时间多,所以这就是为什么先求前两项的原因  
                hash[a*s[i]+b*s[j]+M/2]++;    //(加上M/2的原因是防止下标为负,先求前两项,例如a*s[i]+b*s[j] == 5     
        for(i=1;i<101;i++)  
            for(j=1;j<101;j++)  
                sum+=hash[-(c*s[i]+d*s[j])+M/2];   //与前面例如对应:如果c*s[i]+d*s[j] == -5  那么相加正好等于0,符合题解,正好求出x,故项数在前面加号就是5啦,5那项有多少,-5与之对应的就有多少解……  
        printf("%d\n",sum*16);   //因为 x 是平方,所以正负数的平方都一样,一个x就会有两个解了,4个x当然就有2^4=16个解
    }  
    return 0;  
}

第六题:HDU 2648 shopping

这题刚开始确实不会,研究了好久,还是不会。迫不得已看了下别人的做法,实在高明啊!!

又是一道哈希实质题。地址哈希,唉,这思想也不知道哪个大神想出来的,佩服啊……见识了

#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#define mem(a,b) memset(a,b,sizeof(a))  
typedef long long ll;  
using namespace std;  
#define M 2000000  
int hash[10003];  
int main()  
{  
    int n,m,i,j,k,w,a;  
    string s;  
    while(scanf("%d",&n)!=EOF)  
    {  
        mapq;  //拿map中字符串映射地址,就转换成了整形了,哈希只要能转成整形的怎么都好讲了  
        mem(hash,0);  
        for(i=0; i>s;  
            q[s]=i;   //字符串对应地址,地址从0开始编号  
            if(s=="memory") w=i;   //记住目标字符串的地址  
        }  
        scanf("%d",&m);  
        for(i=0;i>a>>s;  
                hash[q[s]]+=a;   //哈希数组加权值,地址相当于哈希数组下标,简单明了  
            }  
            for(k=0; k

第七题 POJ 1200

这题和上面的一样,也是哈希表……只要找到这个串里能唯一表示地址的那个计算式就行了……

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define pi acos(-1.0)
using namespace std;
typedef long long ll;
#define M 16000000
char s[M];
int a[100],hash[M];
int ;
int main()
{
    int N,NC,num=0,len,i,j,ans=0,sum=0;
    scanf("%d%d",&N,&NC);
    scanf("%s",&s);
    len=strlen(s);
    for(i=0; i=NC的数,因为这样才能唯一的表示一个字符串转换成整形数组的下标地址,而NC最小嘛
        if(!hash[sum])
        {
            ans++;
            hash[sum]=1;
        }
    }
    printf("%d\n",ans);
    return 0;
}



你可能感兴趣的:(哈希表入门题目总结(HDU 1280、1425、2027、3833、1496、2648 POJ 1200))