POJ 2785 解题报告

注: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,后来我的程序改得和网上的一模一样了。同学们可以直接移步到这里:http://www.cnblogs.com/wuyiqi/archive/2012/06/05/2536785.html

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

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

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

int hash(int num){
        return (num+3899971)%3999971;
}

为什么用这种方法可以见http://stackoverflow.com/questions/1145217/why-should-hash-functions-use-a-prime-number-modulus

但是估计看完也只有直观的感受,那就是用素数会让整个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;
}

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

你可能感兴趣的:(数据结构,面试,测试,table)