用单个状态构造日期序列的优雅算法是什么?

时间:2012-08-29 13:23:25

标签: algorithm

给定任何一系列输入日期,其中单个状态为“打开”或“已关闭”,以便至少有一个输入日期(打开状态),这会导致单个日期(已关闭,最大日期)被添加到完成输出序列你会用什么算法来生成服从以下的输出?

1。没有连续的开放日期,也没有连续的关闭日期。

2。对于每个开放日期,只有一个截止日期。

3。第一个日期应为Open,最后一个日期应为Closed。

4。除了第一个开放日期和最后一个关闭日期之外,每个开放日期应该紧跟上一个关闭日期,或换句话说,每个关闭日期应该是下一个开放日期之前的一天。

5。最终日期为已结束日期和最长日期(在此示例中为9999-12-31)

这不是一个家庭作业,我在C#中实现了它,它的生产代码将执行数百万次。性能很重要,是的,但非常可读性。我使用的算法效果很好,但看起来很糟糕。任何语言欢迎。我会在必要时翻译。感谢。

示例1

input:
[2000-01-01,open] 

output: 
[2000-01-01,open]
[9999-12-31,closed]

示例2

input: 
[2000-01-01,open]
[2001-01-01,open]

output: 
[2000-01-01,open]
[2000-12-31,closed]
[2001-01-01,open]
[9999-12-31,closed]

示例3

input: 
[2000-01-01,open]
[2004-04-30,closed]

output: 
[2000-01-01,open]
[2004-04-30,closed]
[2004-05-01,open]
[9999-12-31,closed]

示例4

input: 
[2000-01-01,open]
[2000-03-17,open]
[2002-09-11,closed]
[2003-04-07,closed]

output: 
[2000-01-01,open]
[2000-03-16,closed]
[2000-03-17,open]
[2002-09-11,closed]
[2002-09-12,open]
[2003-04-07,closed]
[2003-04-08,open]
[9999-12-31,closed]

我敢问哪种语言最能解决这类问题?

3 个答案:

答案 0 :(得分:5)

  1. 按日期对输入进行排序。
  2. 迭代输入,跟踪当前状态。
  3. 如果状态已打开且遇到开放日期,请插入关闭日期。
  4. 如果州已关闭且遇到关闭日期,请插入开放日期。
  5. 如果州已关闭并且遇到的开放日期不是上一个截止日期之后的日期,请插入开放日期和关闭日期以填补该空白。
  6. 完成迭代输入后,如果状态为打开,请插入最终关闭日期。
  7. 完成迭代输入后,如果状态已关闭且最终结束日期不是9999-12-31。插入最后的开放和关闭日期。

答案 1 :(得分:0)

您可以先生成所有开放日期的列表,然后通过从第一个开始日期减去一天来计算结束日期:

C#伪代码:

  var opendates = input.Select ( date =>
      date.Type == closing ? date.Date + 1day : date.Date
  ).Sort ();
  closingdates = opendates.Skip (1).Select (date => date - 1).Append ( new Date [] { 9999-12-31 } );

答案 2 :(得分:0)

所以解决方案应该很快,因为性能在这里至关重要。此外,它应支持在线处理,因此当系统运行时,您可以随时添加新的开始/结束日期,并立即获得更新的计划。

由于此问题的主要操作是排序,我建议使用堆。堆中的每个节点都存储一个日期/状态对。该算法以空堆启动,并不断将其作为读取输入进行开发。当有新数据到来时,算法会将其插入到树中,该树需要O(lgN)。当有请求提取时间表时,算法执行有序遍历,其取O(N)。该算法还应该一次平衡自己以获得更好的性能。