如何计算时间范围的交叉点?

时间:2016-06-12 06:37:50

标签: c# .net

我有一个所有行的文本文件:

  

8:30 8:50 1

     

..........

     

20:30 20:35 151

每一行都是In-net中与其相关的新用户连接。

目标是找到数量达到最大值的时间段。 那么,也许有人知道可以帮助我完成这项任务的算法(多个交叉点)?找到这个任务对我来说非常重要(因为我是编程新手),我有一些想法,但我发现它们很糟糕,这就是为什么我应该从数学算法开始,以达到实现目标的最佳方式。

2 个答案:

答案 0 :(得分:0)

你可以这样做:

string[] lines=System.IO.File.ReadAllLines(filePath)
var connections = lines
    .Select(d => d.Split(' '))
    .Select(d => new 
    { 
        From = DateTime.Parse(d[0]), 
        To = DateTime.Parse(d[1]), 
        Connections = int.Parse(d[2]) 
    })
    .OrderByDescending(d=>d.Connections).ToList(); 

连接将包含排序列表,其中前面的结果是

答案 1 :(得分:0)

首先,我们必须做出一些假设。

  1. 假设您正在寻找最长连接时间。
  2. 假设每一行代表一个连接。我们并不清楚 在开始和结束时间之后询问什么是整数 每一行。所以我忽略它。
  3. 这些行按照周期开始时间的增加顺序给出。
  4. 我们可以自由选择任何本地最大值作为答案,以防我们有多个时段具有相同数量的同时连接。
  5. 解决方案的第一阶段是解析。给定一系列行,我们得到System.DateTime对的序列 - 按顺序为每个句点添加一对。

    static Tuple<DateTime, DateTime> Parse(string line)
    {
        var a = line.Split()
                .Take(2)        // take the start and end times only
                .Select(p => 
                      DateTime.ParseExact(p, "H:m",
                                          CultureInfo.InvariantCulture))
                .ToArray();
        return Tuple.Create(a[0], a[1]);
    }
    

    下一阶段是算法本身。它有两个部分。首先,我们发现局部最大值为开始时间,结束时间和连接数的三元组。其次,我们从第一部分产生的集合中选择绝对最大值:

    File.ReadLines(FILE_PATH).Select(Parse).GetLocalMaximums().Max(x=>x.Item3)
    
    File.ReadLines(FILE_PATH).Select(Parse).GetLocalMaximums()
        .Aggregate((x, y) => x.Item3 > y.Item3 ? x : y))
    
    File.ReadLines(FILE_PATH).Select(Parse).GetLocalMaximums()
        .Aggregate((x, y) => x.Item3 >= y.Item3 ? x : y))
    

    最复杂的部分是检测局部最大值。

    1. 取第一个时段A并记下结束时间。然后写下来 它的开始时间是最后一次已知的开始时间。注意有一个目的 写的时间和一个有效的连接。
    2. 选择下一个时段B并写下结束时间。比较开始 B的时间到写的结束时间的最小值。
    3. 如果没有比B的开始时间更短的书面结束时间,那么 此时连接数增加。所以放弃以前 最后一个已知开始时间的值,并将其替换为B&#39的开始 时间。然后继续下一个时期。再次注意还有一个 在这个时候连接,我们还有一个结束时间。所以号码 活动连接的数量始终等于写下的数量 次。
    4. 如果结束时间列表中的值小于B&#39; s,我们 连接数减少,这意味着我们只是通过了 局部最大值(这是数学)。我们必须报告它:产生三元组(最后已知的开始时间,写入结束时间的最小值,数字 结束时间减去一个)。我们不应该计算B的结束时间 我们已经写过了。然后丢弃所有结束时间更少 比B的开始时间,替换最后已知的开始时间,然后继续 到下一个时期。
    5. 当最短结束时间等于B的开头时,就意味着我们已经开始了 丢失了一个连接并同时获得了另一个连接。这意味着 我们必须放弃结束时间并进入下一个时期。
    6. 对我们所有期间的第2步重复。
    7. 本地最大检测的源代码

      static IEnumerable<Tuple<DateTime, DateTime, int>> 
             GetLocalMaximums(this IEnumerable<Tuple<DateTime, DateTime>> ranges)
      {
          DateTime lastStart = DateTime.MinValue;
          var queue = new List<DateTime>();
          foreach (var r in ranges)
          {
              queue.Add(r.Item2);
              var t = queue.Min();
              if (t < r.Item1)
              {
                  yield return Tuple.Create(lastStart, t, queue.Count-1);
                  do
                  {
                      queue.Remove(t);
                      t = queue.Min();
                  } while (t < r.Item1);
               }
      
               if (t == r.Item1) queue.Remove(t);
               else lastStart = r.Item1;
          }
      
          // yield the last local maximum
          if (queue.Count > 0)
              yield return Tuple.Create(lastStart, queue.Min(), queue.Count);
      }
      

      虽然使用List(T)不是最好的决定,但它很容易理解。使用排序版本的列表可以获得更好的性能。用结构替换元组将消除大量的内存分配操作。