http://topic.youkuaiyun.com/u/20081224/16/23041dbb-b0b9-46c5-9ff7-3a4dede2a6e3.html
1、这是今年百度的一道笔试题。给你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
2、偶觉得算法思想可以如下:
输入队列比如是
struct ipChain{
char ip[16];
char date[16];
}ipArray[100000];
在这个ipArray上 维持 2个动态标记: head 初始为0 tail为的index为 ipArray[tail].date - ipArray[head].date <= X 并且 ipArray[tail+1].date - ipArray[head].date > X。
将 tail - head + 1个元素 进行散列,加下每个ip的 count 大于Y的直接 可以输出
以后 tail++, 查看先加入的元素是否 使 ipArray[tail].date - ipArray[head].date > x, 大于 则 head++,且 散列表中其count--,一旦为0,删除之。然后 将新加入的ipArray[tail] 加入散列表 查看是否 count > Y。
这样的话 算法 应该比 O(n)差不了多少。
3、能把哈希函数告诉吗?
就是把IP地址散列到10万的数以内,我是这样做的
例如:192.168.0.1
hash = ((192 × 192) % 100000 + (168 × 168)% 100000 + (0 × 0)% 100000 + (1 * 1) % 100000) % 100000
有冲突就向后找空位
但是效率不高
求一个效率高的哈希函数
4、你自己可以根据 X的大小来选取一个平均的 hash 表长度哈
比如 x = 60(秒)(平均值)
1/60/24 * 1亿 = 7万左右
长度选取 10万应该挺合理的。
hash那就更简单了 IP 0.0.0.0 正好对应 4* 8(bits) = 32位(1个int)
写个函数 int ip_to_int(const char *ip);
将返回的数字 ret % 100000作为哈希数组索引
5、引用 8 楼 huangzhtao 的回复:
能把哈希函数告诉吗?
就是把IP地址散列到10万的数以内,我是这样做的
例如:192.168.0.1
hash = ((192 × 192) % 100000 + (168 × 168)% 100000 + (0 × 0)% 100000 + (1 * 1) % 100000) % 100000
有冲突就向后找空位
但是效率不高
求一个效率高的哈希函数
还有关于冲突 我觉得你的解决方法 不是很理想,找空位的方法万一制定x时间内 ip地址超过10万个呢?所以hash表的 element好好设计下
偶觉得可以
struct hash_element{
const char *ip;
int count;
struct hash_element *next;
};
ip就放 当前被hash的ip地址字符串的地址,count个数 next指向下一个冲突的地址。
这样 hash_elemnt[100000];的一个hash表应该能搞定
6、引用 13 楼 fisher_047 的回复:
引用 9 楼 threeleafzerg007 的回复:
你自己可以根据 X的大小来选取一个平均的 hash 表长度哈
比如 x = 60(秒)(平均值)
1/60/24 * 1亿 = 7万左右
长度选取 10万应该挺合理的。
hash那就更简单了 IP 0.0.0.0 正好对应 4* 8(bits) = 32位(1个int)
写个函数 int ip_to_int(const char *ip);
将返回的数字 ret % 100000作为哈希数组索引
我没太理解9楼的将IP转换成整数的方法,比如说192.0.0.1转换后是1920…
const char *ip = "127.0.0.1";
int a1,a2,a3,a4,result = 0;
sscanf(ip,"%d.%d.%d.%d",&a1,&a2,&a3,&a4);
result |= a1 < < 24;
result |= a2 < < 16;
result |= a3 < < 8;
result |= a4;
7、由于条件上y <100,所以可以用byte数组散列
ip正好可以转成uint32,这样需要内存:
(2^32)b=4G Byte!!
如果就这么回答完毕的话估计是没分了.
可以考虑用链地址法来散列
只散列ip的前3段.
另外,多用位运算估计就可以了.
ip的哈希的问题解决了,然后就可以滚动扫描了