查找攻击IP

这是百度的一道笔试题好像是08年的。给你1亿个ip地址和每个ip访问的时间(00:00:00=<时间<=23:59:59,并且已经按照时间排好序了),然后给定一段时间X,定义在X内如果某IP的访问次数超过Y次,则判定该IP为攻击IP。要求输出所有攻击IP。只有一组测试用例。第一行输入IP记录数(即10万),时间X(10=<X<=120秒),次数Y(2=<Y<=100)。输出按访问的时间顺序输出,IP重复不再输出。
输入示例:(为了方便,只给出8个,意思意思)
8 10 2
10.254.82.126 00:00:39
10.85.124.135 00:00:40
10.254.82.126 00:00:44
10.254.82.126 00:00:44
10.1.82.125 00:00:45
10.85.124.135 00:00:48
10.254.82.126 00:00:48
10.254.82.126 00:00:49
输出示例:
10.254.82.126 
10.85.124.135 

看的论坛上人的解法,先化成小问题,在就是动态规划法统计。但是如果需要hash要分块的话,先要计算出大概每块的大小。如果是120s,那么一块大概为1亿/24/60/60*120大概为13w,那么分成大概10w左右的块就可以了,可以用hash函数ip_to_int(ip)%100000,分成小文件分别保存,注意这个小文件里面的还是按时间有序的。分块的好处在于可以把相同ip分到一块里面。下面是ip_to_int的算法。

#include <iostream>
using namespace std;

unsigned int ip_to_int(char *ip)
{
        int a1;
        int a2;
        int a3;
        int a4;
        int result = 0;
        sscanf(ip, "%d.%d.%d.%d", &a1, &a2, &a3, &a4);
        result |= a1<<24;
        result |= a2<<16;
        result |= a3<<8;
        result |= a4;
        return result;
}
int main()
{
        char *ip = "192.168.1.1";
        unsigned int ret = ip_to_int(ip);
        cout<<ret<<endl;
        return 0;
}

分好之后可以统计在X时间内超过Y次的ip地址了。首先读入数据,那么一个文件中大概占用内存为10w*4(2+2如下结构)大概有400M的内存,如果用一个数组存储的话有元素如下,ip为char,最长为16个字符
struct ipChain{
  char ip[16];
  char date[16];
}ipArray[100000];
这个时候可以用两个offset来标识所读的数组段,这两个分别为head和tail满足以下两点性质:
1)ipArray[tail].date - ipArray[head].date <= X
2) ipArray[tail+1].date - ipArray[head].date > X
也就是所有在时间段X秒内的所有ip,这个时候用散列表map或hash_map统计每个IP的出现次数,如果有大于Y的输出,tail++,把这个时候对应tail的ip的次数+1,如果ipArray[tail].date - ipArray[head].date>X,time[head]--,head++。这样每次前进都有利用前面统计的结果,动态规划方法。

参考:
http://topic.csdn.net/u/20081224/16/23041dbb-b0b9-46c5-9ff7-3a4dede2a6e3.html

你可能感兴趣的:(算法,Date,struct,测试,百度,存储)