代码之家  ›  专栏  ›  技术社区  ›  gene b.

在E(startTime,endTime)的排序列表上进行二进制搜索,以找到给定时间范围(t1,t2)匹配的所有E

  •  0
  • gene b.  · 技术社区  · 4 年前

    我有 Event 目标如下,

    public class Event {
       String name;
       int startTime; // minutes since midnight, e.g 4:15am = 255
       int endTime;   // minutes since midnight, e.g.6:30am = 390
       // + getters/setters
    }
    

    它们按startTime ASC排序,

    events.sort(Comparator.comparing(Event::getStartTime));
    

    事件可以以任何方式重叠。

    我需要获得所有匹配事件的列表( 包括部分 )特定范围 t1,t2 (也指午夜后的分钟数)。

    List<Event> eventsMatching = findMatching(t1, t2); // e.g. between 200,205
    

    我不想浏览整个列表并检查 e.getStartTime() <= t1 && e.getEndTime() >= t2 。由于列表已排序,我应该能够使用 Collections.binarySearch() 在某种程度上。但通常情况下,二进制搜索会找到您要查找的确切对象: int position = Collections.binarySearch(events, key) 。有没有办法使用二进制搜索快速找到匹配的范围?

    2 回复  |  直到 4 年前
        1
  •  4
  •   user17223316 user17223316    4 年前

    您需要检查所有符合 e.startTime <= t1 .

    record Event(String name, int startTime, int endTime) {}
    List<Event> list = Arrays.asList(
        new Event("a", 2, 3), new Event("b", 3, 4),
        new Event("c", 0, 1), new Event("d", 4, 5));
    list.sort(Comparator.comparing(Event::startTime));
    System.out.println("sorted:   " + list);
    int t1 = 2, t2 = 3;
    List<Event> filtered = list.stream()
        .takeWhile(e -> e.startTime() <= t1)
        .peek(e -> System.out.println("checked:  " + e))
        .filter(e -> e.endTime() >= t2)
        .toList();
    System.out.println("filtered: " + filtered);
    

    输出

    sorted:   [Event[name=c, startTime=0, endTime=1], Event[name=a, startTime=2, endTime=3], Event[name=b, startTime=3, endTime=4], Event[name=d, startTime=4, endTime=5]]
    checked:  Event[name=c, startTime=0, endTime=1]
    checked:  Event[name=a, startTime=2, endTime=3]
    filtered: [Event[name=a, startTime=2, endTime=3]]
    
        2
  •  1
  •   Bohemian    4 年前

    二进制搜索对你没有多大帮助,因为你不是在搜索一个基于相等的匹配,而是一个 范围 可以排序的结果,但不能以有助于快速找到匹配项的方式排序。

    除非你要处理很多范围元素(1000个),否则线性(即O(n))过程可以正常工作。

    为了加快速度,请提前按开始日期排序,这样当您遇到开始日期在目标之后的元素时,您对列表的迭代就可以提前退出。

        3
  •  1
  •   Zinedine Benkhider    4 年前

    您应该浏览列表,并在项目不在范围内时停止。就复杂性而言,这是你能做的最好的事情。