前几天个人朋友面试头条,给出了这样一道面试题:面试
有一天的log的数据量,求一天中用户在线峰值和持续时间。算法
他面试结束后与我讨论,让我也作一下,我晚上就用了点时间作了这个题目。数组
写完以后咱们讨论发现由于思路不一样,且他的方法更好,就记录下来跟你们分享一下。spa
/// <summary> /// 登陆日志 /// </summary> public class Log { /// <summary> /// 登陆时间 /// </summary> public int LoginTime { get; set; } /// <summary> /// 登出时间 /// </summary> public int LogoutTime { get; set; } }
由于只求峰值数据,太多的字段没有加。3d
//模拟数据 var logs = new List<Log>{ new Log{ LoginTime=2, LogoutTime=5 }, new Log{ LoginTime=3, LogoutTime=6 }, new Log{ LoginTime=3, LogoutTime=4 }, new Log{ LoginTime=4, LogoutTime=8 }, new Log{ LoginTime=4, LogoutTime=9 }, new Log{ LoginTime=4, LogoutTime=10 }, new Log{ LoginTime=3, LogoutTime=4 }, new Log{ LoginTime=4, LogoutTime=8 }, new Log{ LoginTime=5, LogoutTime=6 }, };
#region 获取每一个小时在线人数 //定义一个数组盛放每一个小时的在线人数 int[] logHigh = new int[24]; int time = 0; while (time < 24) { logHigh[time] = 0; foreach (var log in logs) { if (time >= log.LoginTime && time < log.LogoutTime) { logHigh[time]++; } } time++; } #endregion #region 获取最大在线人数和持续时间 //获取最大在线人数 var max = logHigh[0]; var index = 0; for (int j = 1; j < logHigh.Length; j++) { if (max < logHigh[j]) { max = logHigh[j]; index = j; } } //获取最大在线人数持续时间 var maxIndex = 0; for (var maxI = index + 1; maxI < logHigh.Length; maxI++) { if (logHigh[maxI] == max) { maxIndex = maxI; } else { continue; } } #endregion Console.WriteLine("最大在线人数是:" + max); Console.WriteLine($"起始时间是:{index},结束时间是:{maxIndex + 1},持续时间:{maxIndex + 1 - index}h"); for (var i = 0; i < 24; i++) { Console.WriteLine($"时间在 {i} 到 {i + 1} 点之间在线人数是:{logHigh[i].ToString()}"); } Console.ReadKey();
写完以后咱们对结果,没有问题。又互相看了对方的代码,发现逻辑是不同的。日志
//当天数据容器 var array = new int[24]; //初始化数据 foreach (var item in logs) { //只记录当前在线人数便可 for (int i = item.LoginTime; i < item.LogoutTime; i++) { array[i]++; } } //统计部分 int biggest = 0; //峰值 int biggestLength = 0; //持续时长 int biggestTime = 0; //最大开始时间 for (int i = 0; i < array.Length; i++) { //当前在线人数 var currentValue = array[i]; //存储最大峰值 if (currentValue > biggest) { biggest = currentValue; biggestLength = 0; biggestTime = i; } if (currentValue == biggest) biggestLength++; } //输出部分 for (int i = 0; i < array.Length; i++) { Console.WriteLine($"当前时间:{i} \t 在线人数:{array[i]}"); } Console.WriteLine($"当天最大峰值:{biggest}人,开始时间:{biggestTime}点,持续时间:{biggestLength}h"); Console.ReadKey();
不知道你们看出来咱们两个逻辑上有什么不一样吗?code
其实主要的不一样是第一部分求每一个小时在线人数的思路上的不一样:blog
个人想法是轮询24小时,遍历log数据发如今遍历的时间内就+1;get
他的思路是遍历log数据,在数据的开始结束时间内都+1。it
他这样作的话就在复杂度上少了不少,至少比我少一半的复杂度。
这其实就是一道大厂很是喜欢考的逻辑算法的题目,我朋友这样的算法天然更好:逻辑清晰,复杂度低。
若是你们还有什么更好的解法欢迎写在下面。