博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
POJ 2785 解题报告
阅读量:4204 次
发布时间:2019-05-26

本文共 1772 字,大约阅读时间需要 5 分钟。

注:leetcode的要求是第一列中相同的数只算一次。POJ是单独算的。

比如

4

0 0 0 0 

0 0 0 0

0 0 0 0

0 0 0 0

这组测试数据,leetcode上面要求返回1,而在POJ上要求返回4*4*4*4 = 256。

好吧。上次写POJ解题报告的解题的时间为“2011-03-18 01:41”。现在时间是“2012-10-20 15:48”。我就不继续说下去了。免得自己太难过。。。

这次写POJ这道题的缘由是在准备笔试面试,在leetcode上见到一道题是是求所以a+b+c+d=0的可能的组数。于是看到了POJ这道题的链接。

当时在leetcode的OJ通过的做法是先排序,然后对两行遍历,另外两行一个指针从上往下走,一个指针从下往上走。时间复杂度是O(n^3)。

但在POJ,这是无法通过的。。。

于是,在尝试把前两组遍历,求出所有可能的和,保存在map中,然后遍历后两组,对每一个和sum,在map中找-sum。这样的时间复杂度是O(n^2*log*(n^2))。

但在POJ,这是无法通过的。。。

于是,开始“参考”网上的做法,使用hash。后来提交的时候还是各种RE,后来我的程序改得和网上的一模一样了。同学们可以直接移步到这里:

因为程序一模一样了,我也就不贴程序了。

这道题给我长进是:链式Hash

下面的hash函数使用两个大素数取余,

int hash(int num){

        return (num+3899971)%3999971;
}

为什么用这种方法可以见

但是估计看完也只有直观的感受,那就是用素数会让整个hash表尽可能都用到。当然,用这是由于“数学原理”来理解也就差不多了。。。

int tot;

struct edge{
        int v, next, cnt;
}edge[3999971];
int head[3999971];

这是链式hash表实现的数据结构,实际上没有使用链表,而是使用数组,用数组索引代替指针(原因是在POJ中一次开很大的数组是允许的,这样可以避免每次动态申请空间的时间开销,算是用空间换时间)。head用做索引,指向hash值为s的第一个num。这个num及所有hash值为s的数保存在edge数组中。edge中的每一个元素是一个结构体,保存这个元素的num(用v表示),下一跳在edge数组中的索引,还有num出现了多少次(用cnt表示)。hash值取0~3999970(见hash函数中的取余素数)。所以两个数组开3999971这么大。

这也能看出取hash值的作用:用一个相对较小的空间保存所有可能出现的和,避免一个特大的空间(3999971 vs 2^30,因为每个数的范围为(+-)2^28)。

void add_edge(int num){

        int s=hash(num);
        for(int i = head[s]; i != -1; i = edge[i].next){
        if(edge[i].v == num){
                edge[i].cnt++;
                return ;
        }
}
        edge[tot].v = num;
        edge[tot].cnt = 1;
        edge[tot].next = head[s];
        head[s]=tot++;
}

这是插入hash表的过程。首先对num取hash,根据head找到第一个hash值为s的数在edge中的索引,如果找到,则cnt加1。否则在edge表的末尾(索引为tot,tail of table)保存下这个数的信息(数值num, 计数为1)。注意的是这里让这个新的节点下一跳指向当前的头结点,然后更新头结点为这个新节点。这样实际上将节点插入在了这一系列值的最前列。体会下当head[s]为-1时,即没有值时的情况。这样写要比将新节点报错在链式表的末端要统一。

int find(int num){
int s=hash(num);
for(int i=head[s];i!=-1;i=edge[i].next){
if(edge[i].v == num){
return edge[i].cnt;
}
}
return 0;
}

明白了插入的过程后查找的过程就顺其自然了。如果这条链上都没找到,则该数不存在。

转载地址:http://uxxli.baihongyu.com/

你可能感兴趣的文章
Template模式
查看>>
Observer模式
查看>>
解决openstack novnc一段时间后自动挂断登录不上问题,novncproxy dead but pid file exists
查看>>
构建OpenStack的云基础架构:ManageIQ(转)
查看>>
CentOS 7.0,启用iptables防火墙(转)
查看>>
实战DDD(Domain-Driven Design领域驱动设计:Evans DDD)
查看>>
SSH中各个框架的作用以及Spring AOP,IOC,DI详解
查看>>
openstack juno 配置vmware(vcenter、vsphere)
查看>>
远程debug调试(eclipse)之openstack windows
查看>>
PAAS平台对比:OpenShift VS CloudFoundry【51CTO调研报告】
查看>>
JAX-RS(java restful实现讲解)(转)
查看>>
Spring MVC与JAX-RS比较与分析
查看>>
openstack官方docker介绍
查看>>
[转]在ASP.NET 2.0中操作数据::创建一个数据访问层
查看>>
Linux命令之chmod详解
查看>>
【java小程序实战】小程序注销功能实现
查看>>
Java中子类能否继承父类的私有属性和方法
查看>>
JVM内存模型详解
查看>>
(六) Git--标签管理
查看>>
建造者模式(Builder)-设计模式(三)
查看>>