【问题标题】:Leave just overlapping dates in the list在列表中只保留重叠的日期
【发布时间】:2016-08-22 18:40:18
【问题描述】:

我有一个会话到期时间和会话超时值的列表。 所以我可以得到会话开始时间从过期时间中减去超时。

我知道如何检查两个日期是否重叠:

public boolean isOverlapped(LocalDateTime start1, LocalDateTime end1,
                            LocalDateTime start2, LocalDateTime end2) {
    return (start1.isBefore(end2) || start1.equals(end2)) 
            && (start2.isBefore(end1) || start2.equals(end2));
}

但不知道如何处理日期列表。

结果我想列出最长的重叠(并发)会话链。 感谢任何帮助!

【问题讨论】:

  • “重叠”是日期之间的四位关系。因此,如果每个列表元素都是一个日期,那么列表中的“只有[原文如此] 重叠的日期”意味着什么?
  • 您需要设计一组测试数据,其中包含您感兴趣的“重叠”的所有可能含义,并显示输入和预期输出。我不确定你是否清楚你想要的结果是什么。一种可能的明确定义是识别属于多个间隔的时间跨度,然后输出包含这些时间跨度之一的所有间隔。但是,这可能不是您所说的“重叠”。就目前而言,这个问题可能会以“不清楚你在问什么”而结束。
  • 您的列表如何保存开始日期和结束日期?

标签: java algorithm arraylist


【解决方案1】:

首先,创建一个代表这些会话的新类(如果您还没有):

class Session {
    private LocalDateTime start;
    private LocalDateTime end;  

    public boolean isOverlapped(Session other) {
        return (start.isBefore(other.end) || start.equals(other.end)) 
            && (end.isAfter(other.start) || end.equals(other.start));
    }
    ...     
}

您的输入列表必须是Sessions 的列表。

接下来,这是一个满足您要求的算法;它接受一个列表并检查每个元素是否与列表中的 any 其他元素重叠(除了它自己)。如果是这样,它会将其放入结果列表中:

public static List<Session> filter(List<Session> in) {
    List<Session> result = new ArrayList<>();

    for(Session current : in) {
        for(Session other : in) {
            if(current != other && current.isOverlapped(other)) {
                result.add(current);
                break;
            }
        }
    }

    return result;
}

这里也是一个示例程序:Ideone

结果将是一个列表,其中包含与任何其他会话并发的会话。

【讨论】:

  • 感谢您的帮助!可能问题描述不够清楚。使用建议的算法,我们得到与任何其他会话重叠的会话列表。但是,如果我想获得最长的并发会话链怎么办。有什么想法吗?
  • @user936 这是复杂性的一步。我以后可能会研究一下。
  • 我不知道它是否正确,但我创建了以会话为键的映射,并以重叠会话列表为值。我使用您的过滤器方法几乎没有更改(结果我添加了其他会话)。因此,通过这种方式,我有了地图,而不仅仅是按值列表大小对该地图进行排序并从地图中获取第一个元素。
【解决方案2】:

这是一个相当经典的问题。您没有具体说明您是否想要最长的会话时间或间隔数,但它们的工作方式相同。

首先按开始时间对所有会话进行排序。那么逻辑如下:

current_chain = []
best_chain = []
for session in sessions_sorted_by_start:
    if session doesn't overlap with any session in curent_chain:  [1]
        update best_chain if current_chain is better              [2]
        current_chain = []
    current_chain.insert(session)                                 [3]
update best_chain if current_chain is better                      [2]

这里的想法如下:我们维护一个当前链。如果一个新会话与链中的任何其他会话重叠,我们只需将其添加到链中。如果它不与当前链中的任何会话重叠,则它的开始是从当前链中最远会话的末尾开始向右,因此其他剩余会话不会与当前链中的任何会话重叠(因为它们是按开始日期排序)。这意味着当前链与它的长度一样长,因此我们可以根据任何标准(时间或会话数)检查它是否比迄今为止最好的链([2])更好,并重置它。

现在,为了使其及时线性化,在恒定时间内对 [1] 处的会话和链进行重叠检查会很酷。如果您始终在链中保持最远的会话,这很容易完成。为此,当您在 [3] 处插入新会话时,如果其末端超出当前最远会话的结尾,则更新最远会话,否则不更新。这样,在 [1] 处,您只需要检查与最远会话的重叠,而不是检查所有会话,这使得特定的检查时间恒定,并且整个算法是线性的(如果您不考虑初始排序,即当然是O(n log n))。

【讨论】:

    猜你喜欢
    • 2019-01-02
    • 1970-01-01
    • 1970-01-01
    • 2019-12-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-16
    • 2021-10-12
    相关资源
    最近更新 更多