某公司笔试题

bobpipi 2008-10-17 08:28:53
输入是一个文件,是如下格式, 第一行是数字代表下面的行数(3行),下面的每行分两部分,用空格隔开,第一部分表示IP地址,第二部分表示该IP地址的访问时间,整个文件已经按时间排好序。同时给定两个个阈值,X,Y。X代表某个时间间隔,如3秒,Y代表访问次数,如10次。问题是分析这个文件,然后找出所有在X秒内访问大于Y次的IP地址。(把这样的IP地址定义为攻击地址,找出攻击地址)。说说有什么高效的方法吗。

3
201.220.10.2 22:10:3
201.220.10.3 22:10:3
201.220.10.3 22:10:4
...全文
632 27 打赏 收藏 转发到动态 举报
写回复
用AI写文章
27 条回复
切换为时间正序
请发表友善的回复…
发表回复
ws023 2008-10-27
  • 打赏
  • 举报
回复
输入是一个文件,是如下格式, 第一行是数字代表下面的行数(3行),下面的每行分两部分,用空格隔开,第一部分表示IP地址,第二部分表示该IP地址的访问时间,整个文件已经按时间排好序。同时给定两个个阈值,X,Y。X代表某个时间间隔,如3秒,Y代表访问次数,如10次。问题是分析这个文件,然后找出所有在X秒内访问大于Y次的IP地址。(把这样的IP地址定义为攻击地址,找出攻击地址)。说说有什么高效的方法吗。

第一行是数字代表下面的行数(3行) 这个条件还真不知道什么用。
我会先扫一遍文件,把ip转为unsigned int,把时间转为unsigned int,读入共享内存。一亿条记录800M。
然后我会用sort对文件按ip,时间再进行一次排序。这样就得到一个有序队列,在对这个队列逐步做判断:1、判断ip记录数N,2、N>Y,判断此IP max_time-min_time,3、max_time-min_time>X,判断ip[i+9].time-ip[i].time,i+1<N。
wzyzb 2008-10-26
  • 打赏
  • 举报
回复
mark
rongyunsheng 2008-10-26
  • 打赏
  • 举报
回复
think
Silitex 2008-10-22
  • 打赏
  • 举报
回复
其实感觉这一道题不难:扫描一遍,这样可以快速定位当前时间再过x秒的行数,然后在这中间统计重复出现Y次的地址。
李冬宝 2008-10-22
  • 打赏
  • 举报
回复

不是有一行表示下面有多少条记录的嘛
比如:
2
ip1 time0
ip1 time0
3
ip1 time0
ip1 time1
ip1 time1
4
ip5 time1
ip5 time2
ip5 time3
ip5 time3

通过这个数字,可以跳过很多记录的,快速把需要的纪录找出来,比如time1到time2时间段,只要分析模块3,4就可以了

当然具体得看数据的分布特性。
xylophone21 2008-10-21
  • 打赏
  • 举报
回复
4级表存IP吧:)

IP地址不会太多太满的,类似与疏稀矩阵
绿色夹克衫 2008-10-20
  • 打赏
  • 举报
回复
to:lz

List不用遍历呀,因为是顺序记录的,时间大的在后面,所以只需要从第0个元素开始判断即可。

你说的是Hashtable的遍历吧?如果x很大,y很小确实也不快,而且有可能占用的内存很大,不过你说的那种“unsigned int的大数组,用ip的32位数做小标呢”,
大概需要4G内存吧! 所以这些就是权衡问题,在一定的数量级范围之内作选择。如果你选择的是1年内出现过1次的,那如果用HashTable的话,内存消耗恐怕还要大于4G


不过总之就是这个意思,lz可以自行发挥!
绿色夹克衫 2008-10-18
  • 打赏
  • 举报
回复
to:ls

你说的那种hash不能用,不光是内存大的问题,关键是遍历起来要循环的次数太大了。

有专门的hashtable类,我.net用的多一些,.net里面有Dictionary类(散列hash),
插入数据或查找数据时需要消耗的时间为常量,相比数组赋值要慢,不过相对于读取文件的时间,还是要快很多的。


我用的是List,用数组会快,不过大小不好判断,开始时数组申请的长度不能小于你需要统计的时长范围(10秒)内可能出现的访问次数。
List简单一些,但也会慢一些。
bobpipi 2008-10-18
  • 打赏
  • 举报
回复
to litaoye

感觉只是在最后输出时才遍历一次大数组吧。hash用list做的话,如果list里的项目很多(x很大,y很小),那每次的遍历花费的时间也不小啊,加起来估计不小于大数组的方法。
绿色夹克衫 2008-10-17
  • 打赏
  • 举报
回复
不好意思,忘了说了,我给的只是一个程序结构,不是任何一种编程语言,不要直接用呀!
绿色夹克衫 2008-10-17
  • 打赏
  • 举报
回复
做一个hash,key为ip,value为次数

定义一个数组或可以增删的List

定义一个maxTimeStamp,记录序列中的最大时间(只精确到秒,可能会对最后的统计结果有一定影响,但相信统计数据也能实现找出攻击ip的目的)
定义一个minTimeStamp,记录序列中的最小时间(只精确到秒)

顺序读入文件的ip-〉key,和timestamp(时间),

//将记录写入list

list.add(ip,timestamp);

//判断hash是否存在
if(ip Exist in hash)
{
//判断hash是否>0,如果hash = -1,就表示该ip已经被定义为攻击ip了
if(hash.value >= 0)
{
//hash存在则计数加1
hash.value++;
}
}
else
{
//hash不存在则添加
hash.add(ip,0);
}

//如果时间戳 〉 记录中的最大时间戳
if(timestamp > maxTimeStamp)
{
maxTimeStamp = timestamp;
minTimeStamp = timestamp - 统计时间的长度;
if(minTimeStamp > 0)
{
while(list.timestamp < minTimeStamp)
{
list.removeAt(0);

//hash计数减1
hash.value--;//(对应移除的ip的hash)
if(hash.value == 0)
{
hash.remove();//当hash值为0,则移除该ip对应的hash
}
else if(hash.value > 统计次数)
{
hash.value = -1; //标志值为-1,为攻击ip
}
}
}
}

当所有数据都读完了的时候,遍历hash表,输出hash值为-1或hash值>统计次数的ip

大概就是这样一个思路,感觉最好先对文件做一下预处理,生成索引,这样不用每次统计都作重复的计算
bobpipi 2008-10-17
  • 打赏
  • 举报
回复
我也是这么想的,觉得有点复杂。
youxia000 2008-10-17
  • 打赏
  • 举报
回复
麻烦点的,走一遍

挨个读入数据到 arr,因为是按时间排序了的,那么当读入的部分时间达到X 开始分析,每次读入的时候都要把相同的ip做一个统计,找出arr中次数达到Y的 输出

然后在删除第一个读入的ip,在读入下一个ip,判断时间 是达到X的,不然继续读,达到了就看次数到Y的

很麻烦。。。。不怎么好
码农自来也 2008-10-17
  • 打赏
  • 举报
回复
学习了
lllanm 2008-10-17
  • 打赏
  • 举报
回复
有点难办
bobpipi 2008-10-17
  • 打赏
  • 举报
回复
如果是按时间顺序,就不需要全部放在内存,顺序遍历。一个时间队列(超过x时间间隔的T出队列)就可以了。 不太明白。能否详细些。
destinyac 2008-10-17
  • 打赏
  • 举报
回复
1亿条?
如果是按时间顺序,就不需要全部放在内存,顺序遍历。一个时间队列(超过x时间间隔的T出队列)就可以了。
如果非时间顺序,两种方法:
1:外排,然后再采取上方法。
2:数据“全部保存到内存”中。
根据实际情况,采用某种策略来减少所需内存:例如IP地址,可能前面有很多是重复:
例如:给的数据IP地址前面都是: 201.220.10.*,这样就可以采用二级hash就可以了,前面部分一层,后面一层(根据情况采用更多层hash)。或者树也是不错的方法。
对于时间也是的,也可以采用选择“基准时间”,然后直接整数表示。
例如对于样例:如果取:22:10:3 为时间“基准时间”:0 ,那么 后面的两组数据时间就可以表示成:0 1,这样就可以减少内存使用(当然这个也得看规律了,如果你上年时间,这方法就待考虑了)。另外,如果时间相距非常长,但是时间却是“聚簇”形的,可以考虑采用多个基准时间。

上面说的内存问题,而对于解决算法:我觉得采用桶,可能会好点,因为它无需全部排好序,效率是要快些的。查找的时候,只需在每个桶内找,以及相邻桶之间找。-----当然这个是对于一般的情况而言:如果你说x非常小(小到1秒)或者非常大,或者在x时间间隔的某个段内(也就是某个桶中),不同IP异常之多,这个方法就显得低效了,否则的话,还不如直接排序会更加快速。
destinyac 2008-10-17
  • 打赏
  • 举报
回复
1亿条?
如果是按时间顺序,就不需要全部放在内存,顺序遍历。一个时间队列(超过x时间间隔的T出队列)就可以了。
如果非时间顺序,两种方法:
1:外排,然后再采取上方法。
2:数据“全部保存到内存”中。
根据实际情况,采用某种策略来减少所需内存:例如IP地址,可能前面有很多是重复:
例如:给的数据IP地址前面都是: 201.220.10.*,这样就可以采用二级hash就可以了,前面部分一层,后面一层(根据情况采用更多层hash)。或者树也是不错的方法。
对于时间也是的,也可以采用选择“基准时间”,然后直接整数表示。
例如对于样例:如果取:22:10:3 为时间“基准时间”:0 ,那么 后面的两组数据时间就可以表示成:0 1,这样就可以减少内存使用(当然这个也得看规律了,如果你上年时间,这方法就待考虑了)。另外,如果时间相距非常长,但是时间却是“聚簇”形的,可以考虑采用多个基准时间。

上面说的内存问题,而对于解决算法:我觉得采用桶,可能会好点,因为它无需全部排好序,效率是要快些的。查找的时候,只需在每个桶内找,以及相邻桶之间找。-----当然这个是对于一般的情况而言:如果你说x非常小(小到1秒)或者非常大,或者在x时间间隔的某个段内(也就是某个桶中),不同IP异常之多,这个方法就显得低效了,否则的话,还不如直接排序会更加快速。
bobpipi 2008-10-17
  • 打赏
  • 举报
回复
1亿条,写错了
bobpipi 2008-10-17
  • 打赏
  • 举报
回复
IP用32位,时间用16位,也就是48位,6个byte。1条记录,就是600M左右。不用外排吧,题目没说内存大小。
加载更多回复(7)

33,028

社区成员

发帖
与我相关
我的任务
社区描述
数据结构与算法相关内容讨论专区
社区管理员
  • 数据结构与算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧