时间段内的同时在线最大用户数研究
- 问题描述:
需要统计任意一个时段内的同时在线最大用户量,比如统计上个月,上个周,今天凌晨到当前时间为止等等。不失一般性,我们用 start表示统计的开始时间,用end表示统计的结束时间,我们统计在区间[start,end]中的某个时间点达到最值。
定义一个登陆日志表,结构如下:
ID(主键)
login_time(登陆时间)
logout_time(退出时间)
1
2018-1-1 12:12:12
2018-1-1 12:12:25
2
2018-1-1 12:12:13
2018-1-1 12:12:22
3
2018-1-1 12:12:14
4
2018-1-1 12:12:15
2018-1-1 12:12:16
- 规定
假如在时间“2018-1-1 10:10:10”(系统记录时间的最小单位,若你记录到毫秒,那么这个时间点就是毫秒)这个点上,有人退出,有人登陆,意思就是说有人在这个点上退出了,而有人在这个点上登陆了(这种巧合一般不常见)。那么我们规定这个点上的同时在线用户数等于:
在这个点上退出用户的用户数+在这个点上未退出的用户数+这个点上新登陆的用户数
- 解决方案
一行记录表示一个人的登陆登出(若还没有退出则可以把退出时间默认为无穷大),就是一个时间区间。现在要求取的是在区间[start,end]时间中的同时在线最大用户量,满足这个要求的行必须是: 它的登陆登出时间构成的区间与要求的时间区间的交集必须不允许为空集。通过这样的方式我们可以取出满足要求的时间区间。现在问题转换成了去求取这些满足需求的区间中,交集涵盖区间最多的那个交集(可能有多个)的区间数量,
图一
就像图一样,标记的1,2这两个交集涵盖的区间都是三个,若上面五个不同颜色的线代表不同的登陆记录,那么可以得知同时在线最大用户数是3.
简化问题:
区间是二维的,不太方便思考,准备转向一维空间去考虑这个问题。我们可以注意到这么一个事实,将当前用户数设为X, 当有用户登录时,X++; 而到用户退出时,X--;所以同时在线最大用户数一定出现在登录时刻;
故现在我只要去枚举所有的登录时间,在这些登录时间中去寻找一个时间,使得这个时间落入到最大的时间区间中去。
算法如下:
定义数据结构:
Class RangeTime{
Date start;
Date end;
}
假设所有满足查询区间[start,end]的时间区间集合为RangeTime[ ] rangeTimes;
执行如下:
int maxNum = 0;
int curNum = 0;
Date time ;
for i in rangeTimes{
curNum = 0;
for j in rangeTimes{
If (rangeTimes[j].in( rangeTimes[i].start )){
curNum++;
} //
}
If(curNun > maxNun){
maxNun = curNun ;
time = rangeTimes[i].start ;
}
}
当然,上面的算法可以先将时间区间集合按照登录时间进行排序,假如排序后的集合定义为:
RangeTime[ ] rangeTimesOrder; //通过登录时间进行排序后的区间集合。
int maxNum = 0;
int curNum = 0;
Date time ;
For( int i=1;i < rangeTimes.length; i++){
curNum = 0;
For(int j=0; j >=i; j++){
If (rangeTimes[j].in( rangeTimes[i].start )){
curNum++;
} //
}
If(curNun > maxNun){
maxNun = curNun ;
time = rangeTimes[i].start ;
}
}
- 证明
上面是通过感性认识觉得最值出现在登录时刻,但没有严格的证明。
假设满足时间区间[start,end]的登录登出集合为:[a1,b1],[a2,b2]....[an,bn];
那么这些区间由数字{a1,a2,..an,b1,b2,..bn}表示;必定有最值出现在这些数字当中。因为我们的在线用户数只有在登录登出时候才有变化,其他时间没有变化。
我们证明最值一定出现在ai上(ai表示一个登陆时间)即可。
首先我们规定了如下公式
计算某时刻的在线用户量公式如下:
在这个点上退出用户的用户数+在这个点上未退出的用户数+这个点上新登陆的用户数
假设在Bi上取得最值,Bi是一个退出时刻;
- Bi时刻也有登陆的用户,那么不需要证明,因为这个最值也出现在了登陆时刻,即某个Ak.
- Bi时刻没有登陆用户,那么在Bi之前一定是一个登陆点,若是一个退出点,那么Bi时刻不可能取到最值。在Bi时刻后的一个任意小区间内一定不是最值,