Finding overlapping time intervals











up vote
8
down vote

favorite
3













You have two lists with meetings scheduling (start time, end time). Meetings in single list don't intersect. Find all intersecting meetings across the two lists.




Is my complexity $O(N M)$? If I use binary search I might get $O(N log M)$. Can you think of a better algorithm?



For simplicity, I didn't use DateTime. I just assumed meetings are in round hours.



using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication2
{

public class IntersectingMeetings
{
public IntersectingMeetings()
{
MeetingList meetingList1 = new MeetingList();
MeetingList meetingList2 = new MeetingList();
meetingList1.AddMeeting(2,3);
meetingList1.AddMeeting(1,2);

meetingList1.AddMeeting(4,6);

meetingList2.AddMeeting(2,3);
meetingList2.AddMeeting(3,4);
meetingList2.AddMeeting(5,6);
List<Meeting> intersectionsList = FindInterSections(meetingList1, meetingList2);
}

private List<Meeting> FindInterSections(MeetingList meetingList1,MeetingList meetingList2)
{
meetingList1.list.Sort();
meetingList2.list.Sort();
List<Meeting> intersectingList = new List<Meeting>();
foreach (var item in meetingList1.list)
{
foreach (var other in meetingList2.list)
{
if ((item.StartTime >= other.StartTime && item.EndTime <= other.EndTime) ||
(other.StartTime >=item.StartTime && other.EndTime <=item.EndTime))
{
intersectingList.Add(item);
intersectingList.Add(other);
}
}
}
return intersectingList;
}
}


public class MeetingList
{
public List<Meeting> list;
public MeetingList()
{
list = new List<Meeting>();
}
public void AddMeeting(int start, int end)
{
list.Add(new Meeting(start,end));
}
}

public class Meeting : IComparable<Meeting>
{
public int StartTime { set; get; }
public int EndTime { set; get; }

public Meeting(int start, int end)
{
StartTime = start;
EndTime = end;
}

public int CompareTo(Meeting other)
{
if (StartTime > other.StartTime)
{
return 1;
}
else if (StartTime < other.StartTime)
{
return -1;
}
return 0;
}
}
}


This is one solution of the problem I have found.



An efficient approach is to first sort the intervals according to starting time. Once we have the sorted intervals, we can combine all intervals in a linear traversal. The idea is, in sorted array of intervals, if interval[i] doesn't overlap with interval[i-1], then interval[i+1] cannot overlap with interval[i-1] because starting time of interval[i+1] must be greater than or equal to interval[i]. Following is the detailed step-by-step algorithm.










share|improve this question
























  • If I understand you correctly and both lists are sorted - finding intersection would be equivalent to merging these two sorted lists and can be done with complexity of O(m+n)
    – sha
    Dec 6 '14 at 23:32










  • This is not quite Merge sort, since there is no equality here, you need to test for intersection which can be in 4 different use cases.
    – Gilad
    Dec 6 '14 at 23:33






  • 1




    Still, if they are sorted - I'm pretty sure you can get away with m+n. I will try to write it a bit later.
    – sha
    Dec 6 '14 at 23:35










  • This is marked "interview-questions". In the interview, did they give you any indication that time complexity was an evaluation criteria, or that there would be very large numbers of meetings involved?
    – Ben Aaronson
    Dec 10 '14 at 18:08










  • @BenAaronson it wasn't my Interview, but I think that time complexity is always an issue.
    – Gilad
    Dec 10 '14 at 18:15















up vote
8
down vote

favorite
3













You have two lists with meetings scheduling (start time, end time). Meetings in single list don't intersect. Find all intersecting meetings across the two lists.




Is my complexity $O(N M)$? If I use binary search I might get $O(N log M)$. Can you think of a better algorithm?



For simplicity, I didn't use DateTime. I just assumed meetings are in round hours.



using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication2
{

public class IntersectingMeetings
{
public IntersectingMeetings()
{
MeetingList meetingList1 = new MeetingList();
MeetingList meetingList2 = new MeetingList();
meetingList1.AddMeeting(2,3);
meetingList1.AddMeeting(1,2);

meetingList1.AddMeeting(4,6);

meetingList2.AddMeeting(2,3);
meetingList2.AddMeeting(3,4);
meetingList2.AddMeeting(5,6);
List<Meeting> intersectionsList = FindInterSections(meetingList1, meetingList2);
}

private List<Meeting> FindInterSections(MeetingList meetingList1,MeetingList meetingList2)
{
meetingList1.list.Sort();
meetingList2.list.Sort();
List<Meeting> intersectingList = new List<Meeting>();
foreach (var item in meetingList1.list)
{
foreach (var other in meetingList2.list)
{
if ((item.StartTime >= other.StartTime && item.EndTime <= other.EndTime) ||
(other.StartTime >=item.StartTime && other.EndTime <=item.EndTime))
{
intersectingList.Add(item);
intersectingList.Add(other);
}
}
}
return intersectingList;
}
}


public class MeetingList
{
public List<Meeting> list;
public MeetingList()
{
list = new List<Meeting>();
}
public void AddMeeting(int start, int end)
{
list.Add(new Meeting(start,end));
}
}

public class Meeting : IComparable<Meeting>
{
public int StartTime { set; get; }
public int EndTime { set; get; }

public Meeting(int start, int end)
{
StartTime = start;
EndTime = end;
}

public int CompareTo(Meeting other)
{
if (StartTime > other.StartTime)
{
return 1;
}
else if (StartTime < other.StartTime)
{
return -1;
}
return 0;
}
}
}


This is one solution of the problem I have found.



An efficient approach is to first sort the intervals according to starting time. Once we have the sorted intervals, we can combine all intervals in a linear traversal. The idea is, in sorted array of intervals, if interval[i] doesn't overlap with interval[i-1], then interval[i+1] cannot overlap with interval[i-1] because starting time of interval[i+1] must be greater than or equal to interval[i]. Following is the detailed step-by-step algorithm.










share|improve this question
























  • If I understand you correctly and both lists are sorted - finding intersection would be equivalent to merging these two sorted lists and can be done with complexity of O(m+n)
    – sha
    Dec 6 '14 at 23:32










  • This is not quite Merge sort, since there is no equality here, you need to test for intersection which can be in 4 different use cases.
    – Gilad
    Dec 6 '14 at 23:33






  • 1




    Still, if they are sorted - I'm pretty sure you can get away with m+n. I will try to write it a bit later.
    – sha
    Dec 6 '14 at 23:35










  • This is marked "interview-questions". In the interview, did they give you any indication that time complexity was an evaluation criteria, or that there would be very large numbers of meetings involved?
    – Ben Aaronson
    Dec 10 '14 at 18:08










  • @BenAaronson it wasn't my Interview, but I think that time complexity is always an issue.
    – Gilad
    Dec 10 '14 at 18:15













up vote
8
down vote

favorite
3









up vote
8
down vote

favorite
3






3






You have two lists with meetings scheduling (start time, end time). Meetings in single list don't intersect. Find all intersecting meetings across the two lists.




Is my complexity $O(N M)$? If I use binary search I might get $O(N log M)$. Can you think of a better algorithm?



For simplicity, I didn't use DateTime. I just assumed meetings are in round hours.



using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication2
{

public class IntersectingMeetings
{
public IntersectingMeetings()
{
MeetingList meetingList1 = new MeetingList();
MeetingList meetingList2 = new MeetingList();
meetingList1.AddMeeting(2,3);
meetingList1.AddMeeting(1,2);

meetingList1.AddMeeting(4,6);

meetingList2.AddMeeting(2,3);
meetingList2.AddMeeting(3,4);
meetingList2.AddMeeting(5,6);
List<Meeting> intersectionsList = FindInterSections(meetingList1, meetingList2);
}

private List<Meeting> FindInterSections(MeetingList meetingList1,MeetingList meetingList2)
{
meetingList1.list.Sort();
meetingList2.list.Sort();
List<Meeting> intersectingList = new List<Meeting>();
foreach (var item in meetingList1.list)
{
foreach (var other in meetingList2.list)
{
if ((item.StartTime >= other.StartTime && item.EndTime <= other.EndTime) ||
(other.StartTime >=item.StartTime && other.EndTime <=item.EndTime))
{
intersectingList.Add(item);
intersectingList.Add(other);
}
}
}
return intersectingList;
}
}


public class MeetingList
{
public List<Meeting> list;
public MeetingList()
{
list = new List<Meeting>();
}
public void AddMeeting(int start, int end)
{
list.Add(new Meeting(start,end));
}
}

public class Meeting : IComparable<Meeting>
{
public int StartTime { set; get; }
public int EndTime { set; get; }

public Meeting(int start, int end)
{
StartTime = start;
EndTime = end;
}

public int CompareTo(Meeting other)
{
if (StartTime > other.StartTime)
{
return 1;
}
else if (StartTime < other.StartTime)
{
return -1;
}
return 0;
}
}
}


This is one solution of the problem I have found.



An efficient approach is to first sort the intervals according to starting time. Once we have the sorted intervals, we can combine all intervals in a linear traversal. The idea is, in sorted array of intervals, if interval[i] doesn't overlap with interval[i-1], then interval[i+1] cannot overlap with interval[i-1] because starting time of interval[i+1] must be greater than or equal to interval[i]. Following is the detailed step-by-step algorithm.










share|improve this question
















You have two lists with meetings scheduling (start time, end time). Meetings in single list don't intersect. Find all intersecting meetings across the two lists.




Is my complexity $O(N M)$? If I use binary search I might get $O(N log M)$. Can you think of a better algorithm?



For simplicity, I didn't use DateTime. I just assumed meetings are in round hours.



using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication2
{

public class IntersectingMeetings
{
public IntersectingMeetings()
{
MeetingList meetingList1 = new MeetingList();
MeetingList meetingList2 = new MeetingList();
meetingList1.AddMeeting(2,3);
meetingList1.AddMeeting(1,2);

meetingList1.AddMeeting(4,6);

meetingList2.AddMeeting(2,3);
meetingList2.AddMeeting(3,4);
meetingList2.AddMeeting(5,6);
List<Meeting> intersectionsList = FindInterSections(meetingList1, meetingList2);
}

private List<Meeting> FindInterSections(MeetingList meetingList1,MeetingList meetingList2)
{
meetingList1.list.Sort();
meetingList2.list.Sort();
List<Meeting> intersectingList = new List<Meeting>();
foreach (var item in meetingList1.list)
{
foreach (var other in meetingList2.list)
{
if ((item.StartTime >= other.StartTime && item.EndTime <= other.EndTime) ||
(other.StartTime >=item.StartTime && other.EndTime <=item.EndTime))
{
intersectingList.Add(item);
intersectingList.Add(other);
}
}
}
return intersectingList;
}
}


public class MeetingList
{
public List<Meeting> list;
public MeetingList()
{
list = new List<Meeting>();
}
public void AddMeeting(int start, int end)
{
list.Add(new Meeting(start,end));
}
}

public class Meeting : IComparable<Meeting>
{
public int StartTime { set; get; }
public int EndTime { set; get; }

public Meeting(int start, int end)
{
StartTime = start;
EndTime = end;
}

public int CompareTo(Meeting other)
{
if (StartTime > other.StartTime)
{
return 1;
}
else if (StartTime < other.StartTime)
{
return -1;
}
return 0;
}
}
}


This is one solution of the problem I have found.



An efficient approach is to first sort the intervals according to starting time. Once we have the sorted intervals, we can combine all intervals in a linear traversal. The idea is, in sorted array of intervals, if interval[i] doesn't overlap with interval[i-1], then interval[i+1] cannot overlap with interval[i-1] because starting time of interval[i+1] must be greater than or equal to interval[i]. Following is the detailed step-by-step algorithm.







c# datetime interview-questions complexity interval






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Dec 10 '14 at 23:25









Jamal

30.2k11115226




30.2k11115226










asked Dec 6 '14 at 19:13









Gilad

1,25431526




1,25431526












  • If I understand you correctly and both lists are sorted - finding intersection would be equivalent to merging these two sorted lists and can be done with complexity of O(m+n)
    – sha
    Dec 6 '14 at 23:32










  • This is not quite Merge sort, since there is no equality here, you need to test for intersection which can be in 4 different use cases.
    – Gilad
    Dec 6 '14 at 23:33






  • 1




    Still, if they are sorted - I'm pretty sure you can get away with m+n. I will try to write it a bit later.
    – sha
    Dec 6 '14 at 23:35










  • This is marked "interview-questions". In the interview, did they give you any indication that time complexity was an evaluation criteria, or that there would be very large numbers of meetings involved?
    – Ben Aaronson
    Dec 10 '14 at 18:08










  • @BenAaronson it wasn't my Interview, but I think that time complexity is always an issue.
    – Gilad
    Dec 10 '14 at 18:15


















  • If I understand you correctly and both lists are sorted - finding intersection would be equivalent to merging these two sorted lists and can be done with complexity of O(m+n)
    – sha
    Dec 6 '14 at 23:32










  • This is not quite Merge sort, since there is no equality here, you need to test for intersection which can be in 4 different use cases.
    – Gilad
    Dec 6 '14 at 23:33






  • 1




    Still, if they are sorted - I'm pretty sure you can get away with m+n. I will try to write it a bit later.
    – sha
    Dec 6 '14 at 23:35










  • This is marked "interview-questions". In the interview, did they give you any indication that time complexity was an evaluation criteria, or that there would be very large numbers of meetings involved?
    – Ben Aaronson
    Dec 10 '14 at 18:08










  • @BenAaronson it wasn't my Interview, but I think that time complexity is always an issue.
    – Gilad
    Dec 10 '14 at 18:15
















If I understand you correctly and both lists are sorted - finding intersection would be equivalent to merging these two sorted lists and can be done with complexity of O(m+n)
– sha
Dec 6 '14 at 23:32




If I understand you correctly and both lists are sorted - finding intersection would be equivalent to merging these two sorted lists and can be done with complexity of O(m+n)
– sha
Dec 6 '14 at 23:32












This is not quite Merge sort, since there is no equality here, you need to test for intersection which can be in 4 different use cases.
– Gilad
Dec 6 '14 at 23:33




This is not quite Merge sort, since there is no equality here, you need to test for intersection which can be in 4 different use cases.
– Gilad
Dec 6 '14 at 23:33




1




1




Still, if they are sorted - I'm pretty sure you can get away with m+n. I will try to write it a bit later.
– sha
Dec 6 '14 at 23:35




Still, if they are sorted - I'm pretty sure you can get away with m+n. I will try to write it a bit later.
– sha
Dec 6 '14 at 23:35












This is marked "interview-questions". In the interview, did they give you any indication that time complexity was an evaluation criteria, or that there would be very large numbers of meetings involved?
– Ben Aaronson
Dec 10 '14 at 18:08




This is marked "interview-questions". In the interview, did they give you any indication that time complexity was an evaluation criteria, or that there would be very large numbers of meetings involved?
– Ben Aaronson
Dec 10 '14 at 18:08












@BenAaronson it wasn't my Interview, but I think that time complexity is always an issue.
– Gilad
Dec 10 '14 at 18:15




@BenAaronson it wasn't my Interview, but I think that time complexity is always an issue.
– Gilad
Dec 10 '14 at 18:15










4 Answers
4






active

oldest

votes

















up vote
7
down vote



accepted










You could make the Meeting class generic with the T : IComparable<T> constraint. Thus you'll be able to use any type as a time value:



[DebuggerDisplay("{Start} .. {End}")]
public sealed class Meeting<T>
where T : IComparable<T>
{
// You can replace these readonly fields with the auto-properties { get; private set; }:
public readonly T Start;
public readonly T End;

public Meeting(T start, T end)
{
Start = start;
End = end;
}
}


Next you need a comparer:



public sealed class MeetingComparer<T> : IEqualityComparer<Meeting<T>>
where T : IComparable<T>
{
public bool Equals(Meeting<T> x, Meeting<T> y)
{
// We can use only 2 sequential comparisons to check for the intersection:
return x.Start.CompareTo(y.Start) >= 0
? x.Start.CompareTo(y.End) <= 0
: y.Start.CompareTo(x.End) <= 0;
}

public int GetHashCode(Meeting<T> obj)
{
// Make all meetings have the same hash code.
// In this case the Equals method will be called for each object.
return 1;
}
}


And finally you could use LINQ to find the intersecting meetings:



private static IEnumerable<Meeting<T>> FindIntersections<T>(IEnumerable<Meeting<T>> list1,
IEnumerable<Meeting<T>> list2)
where T : IComparable<T>
{
return list1.Join(list2, p => p, p => p,
(a, b) => new { a, b }, new MeetingComparer<T>())
.SelectMany(p => p);
}


Sample:



var list1 = new List<Meeting<int>>
{
new Meeting<int>(0, 1),
new Meeting<int>(100, 111),
new Meeting<int>(20, 41),
new Meeting<int>(10, 11)
};
var list2 = new List<Meeting<int>>
{
new Meeting<int>(2, 3),
new Meeting<int>(105, 106),
new Meeting<int>(40, 41),
new Meeting<int>(15, 16)
};

var intersection = FindIntersections(list1, list2);


EDIT

Try this code to find intersections of the sorted sets. It has complexity $O(N+M)$:



private static IEnumerable<Meeting<T>> FindIntersections<T>(IEnumerable<Meeting<T>> listX,
IEnumerable<Meeting<T>> listY)
where T : IComparable<T>
{
var iteratorX = listX.GetEnumerator();
var iteratorY = listY.GetEnumerator();
Meeting<T> lastX = null;
Meeting<T> lastY = null;
iteratorX.MoveNext();
iteratorY.MoveNext();
while (iteratorX.Current != null && iteratorY.Current != null)
{
Meeting<T> x = iteratorX.Current;
Meeting<T> y = iteratorY.Current;

// Move iterators if needed:
if (x.End.CompareTo(y.Start) < 0)
{
iteratorX.MoveNext();
continue;
}
if (y.End.CompareTo(x.Start) < 0)
{
iteratorY.MoveNext();
continue;
}

// Add items to the resulting set, if the items aren't already there:
if (lastX != x)
{
yield return x;
lastX = x;
}
if (lastY != y)
{
yield return y;
lastY = y;
}

// Determine which iterator should be moved first:
if (y.End.CompareTo(x.End) >= 0)
{
iteratorX.MoveNext();
}
else
{
iteratorY.MoveNext();
}
}
}


The method above:




  • Returns a set of the unique Meeting<T>s.

  • Supports case if one range overlaps several ranges in another set.






share|improve this answer






























    up vote
    7
    down vote













    Your intersection code only catches cases where a meeting is entirely within the time of another meeting. For example, it will not catch the overlap in 10am-2pm and 1pm-4pm. Instead, its easier to check for non-intersection, and then negate. This is a popular approach to checking for intersection in rectangles.



    if (!(item.StartTime > other.endTime || item.endTime < other.StartTime))  {
    // overlap
    }


    As others have mentioned the algorithmic improvement is to use a merge to get O(M + N) complexity. The tricky part is that you compare the ends of the meeting times to decide which to advance.



    Imagine one list with 1 all day meeting and the other with meetings every hour. The first overlaps works just fine, but the all day meeting started first and if you advance that list your search is ended prematurely.



    If you advance the list which has the earlier ending meeting you will be fine since that meeting ends before the other list's next item starts, you won't miss any overlaps.



    int meet1 = 0;
    int meet2 = 0;

    while (meet1 < list1.Count && meet2 < list2.Count) {
    if (intersects(list1[meet1], list2[meet2]) {
    // add to list
    }
    if (list1[meet1].endTime < list2[meet2].endTime) {
    ++meet1;
    } else {
    ++meet2;
    }
    }


    (feel free to edit and flesh this out)






    share|improve this answer























    • (item.StartTime > other.endTime || other.endTime < item.StartTime) is the same question twice
      – Ryan Heitner
      Dec 1 at 17:27










    • @RyanHeitner fixed
      – ryanpattison
      9 mins ago


















    up vote
    5
    down vote













    If you don't count the "sorting of the lists" itself, you can iterate through both lists at the same time in a loop (while, not foreach) and only once which would be O(M+N) or even less: O(M+N) is a maximum, for "good sets" it can go as low as O(M) or O(N) depending on overlaps (thanks for pointing that out in the comments)



    It's too late here for a complete code, but here's a rundown with some pseudocode (comparison methods) to show the algorithm I would use... (EDIT2: Updated the comparison and validated it against several overlapping scenarios. The "isBefore" was a bit sketchy - "end is before other end" should do the trick)



    I still don't think there is a much faster solution... LINQ might make it more "versatile" but certainly not "more efficient" IMHO - with all that method calling in between...



    index1 = 0;
    index2 = 0;

    // as soon as the first list is exhausted, there can be no more overlaps
    while (index1 < list1.Count && index2 < list2.Count)
    {
    // check for overlapping timeframe in either direction...
    if (list1[index1].StartTime < list2[index2].EndTime &&
    list1[index1].EndTime > list2[index2].StartTime)
    {
    // overlaps - do whatever...
    }

    // Advance the one list that has the "older" ending time,
    // doesn't matter whicht if both are equal.
    if (list1[index1].EndTime < list2[index2].EndTime)
    index1++;
    else
    index2++;
    }





    share|improve this answer























    • It actually will be O(min(m,n)) :)
      – sha
      Dec 7 '14 at 0:36






    • 1




      @sha Only one of index1 or index2 is incremented so in the worst case one list reaches the end and the other is just shy of its end. O(M + N).
      – ryanpattison
      Dec 7 '14 at 3:59












    • isBefore will miss some intersections. list1=[(2,3),(4,5)] list2=[(1,5)] would fail to find the overlap between (4,5) and (1,5).
      – ryanpattison
      Dec 7 '14 at 6:21










    • Interesting... I shall have to look into a more precise definition of that. I'm still certain it can be done by only going through the sorted lists once, as I did that before.
      – Roman Gruber
      Dec 10 '14 at 17:12


















    up vote
    4
    down vote













    I would make the MeetingList simpler and take both conditions out of the if for better maintainability:



    public class IntersectingMeetings
    {
    public static List<Meeting> FindInterSections(MeetingList meetingList1, MeetingList meetingList2)
    {
    meetingList1.Sort();
    meetingList2.Sort();
    List<Meeting> intersectingList = new List<Meeting>();
    foreach (var first in meetingList1)
    {
    foreach (var second in meetingList2)
    {
    bool case1 = (first.StartTime >= second.StartTime && first.EndTime <= second.EndTime);
    bool case2 = (second.StartTime >= first.StartTime && second.EndTime <= first.EndTime);

    if (case1 || case2)
    {
    intersectingList.Add(first);
    intersectingList.Add(second);
    }
    }
    }
    return intersectingList;
    }
    }


    public class MeetingList : List<Meeting>
    {
    public void AddMeeting(int start, int end)
    {
    Add(new Meeting(start, end));
    }
    }





    share|improve this answer























      Your Answer





      StackExchange.ifUsing("editor", function () {
      return StackExchange.using("mathjaxEditing", function () {
      StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
      StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
      });
      });
      }, "mathjax-editing");

      StackExchange.ifUsing("editor", function () {
      StackExchange.using("externalEditor", function () {
      StackExchange.using("snippets", function () {
      StackExchange.snippets.init();
      });
      });
      }, "code-snippets");

      StackExchange.ready(function() {
      var channelOptions = {
      tags: "".split(" "),
      id: "196"
      };
      initTagRenderer("".split(" "), "".split(" "), channelOptions);

      StackExchange.using("externalEditor", function() {
      // Have to fire editor after snippets, if snippets enabled
      if (StackExchange.settings.snippets.snippetsEnabled) {
      StackExchange.using("snippets", function() {
      createEditor();
      });
      }
      else {
      createEditor();
      }
      });

      function createEditor() {
      StackExchange.prepareEditor({
      heartbeatType: 'answer',
      convertImagesToLinks: false,
      noModals: true,
      showLowRepImageUploadWarning: true,
      reputationToPostImages: null,
      bindNavPrevention: true,
      postfix: "",
      imageUploader: {
      brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
      contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
      allowUrls: true
      },
      onDemand: true,
      discardSelector: ".discard-answer"
      ,immediatelyShowMarkdownHelp:true
      });


      }
      });














      draft saved

      draft discarded


















      StackExchange.ready(
      function () {
      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f71896%2ffinding-overlapping-time-intervals%23new-answer', 'question_page');
      }
      );

      Post as a guest















      Required, but never shown

























      4 Answers
      4






      active

      oldest

      votes








      4 Answers
      4






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes








      up vote
      7
      down vote



      accepted










      You could make the Meeting class generic with the T : IComparable<T> constraint. Thus you'll be able to use any type as a time value:



      [DebuggerDisplay("{Start} .. {End}")]
      public sealed class Meeting<T>
      where T : IComparable<T>
      {
      // You can replace these readonly fields with the auto-properties { get; private set; }:
      public readonly T Start;
      public readonly T End;

      public Meeting(T start, T end)
      {
      Start = start;
      End = end;
      }
      }


      Next you need a comparer:



      public sealed class MeetingComparer<T> : IEqualityComparer<Meeting<T>>
      where T : IComparable<T>
      {
      public bool Equals(Meeting<T> x, Meeting<T> y)
      {
      // We can use only 2 sequential comparisons to check for the intersection:
      return x.Start.CompareTo(y.Start) >= 0
      ? x.Start.CompareTo(y.End) <= 0
      : y.Start.CompareTo(x.End) <= 0;
      }

      public int GetHashCode(Meeting<T> obj)
      {
      // Make all meetings have the same hash code.
      // In this case the Equals method will be called for each object.
      return 1;
      }
      }


      And finally you could use LINQ to find the intersecting meetings:



      private static IEnumerable<Meeting<T>> FindIntersections<T>(IEnumerable<Meeting<T>> list1,
      IEnumerable<Meeting<T>> list2)
      where T : IComparable<T>
      {
      return list1.Join(list2, p => p, p => p,
      (a, b) => new { a, b }, new MeetingComparer<T>())
      .SelectMany(p => p);
      }


      Sample:



      var list1 = new List<Meeting<int>>
      {
      new Meeting<int>(0, 1),
      new Meeting<int>(100, 111),
      new Meeting<int>(20, 41),
      new Meeting<int>(10, 11)
      };
      var list2 = new List<Meeting<int>>
      {
      new Meeting<int>(2, 3),
      new Meeting<int>(105, 106),
      new Meeting<int>(40, 41),
      new Meeting<int>(15, 16)
      };

      var intersection = FindIntersections(list1, list2);


      EDIT

      Try this code to find intersections of the sorted sets. It has complexity $O(N+M)$:



      private static IEnumerable<Meeting<T>> FindIntersections<T>(IEnumerable<Meeting<T>> listX,
      IEnumerable<Meeting<T>> listY)
      where T : IComparable<T>
      {
      var iteratorX = listX.GetEnumerator();
      var iteratorY = listY.GetEnumerator();
      Meeting<T> lastX = null;
      Meeting<T> lastY = null;
      iteratorX.MoveNext();
      iteratorY.MoveNext();
      while (iteratorX.Current != null && iteratorY.Current != null)
      {
      Meeting<T> x = iteratorX.Current;
      Meeting<T> y = iteratorY.Current;

      // Move iterators if needed:
      if (x.End.CompareTo(y.Start) < 0)
      {
      iteratorX.MoveNext();
      continue;
      }
      if (y.End.CompareTo(x.Start) < 0)
      {
      iteratorY.MoveNext();
      continue;
      }

      // Add items to the resulting set, if the items aren't already there:
      if (lastX != x)
      {
      yield return x;
      lastX = x;
      }
      if (lastY != y)
      {
      yield return y;
      lastY = y;
      }

      // Determine which iterator should be moved first:
      if (y.End.CompareTo(x.End) >= 0)
      {
      iteratorX.MoveNext();
      }
      else
      {
      iteratorY.MoveNext();
      }
      }
      }


      The method above:




      • Returns a set of the unique Meeting<T>s.

      • Supports case if one range overlaps several ranges in another set.






      share|improve this answer



























        up vote
        7
        down vote



        accepted










        You could make the Meeting class generic with the T : IComparable<T> constraint. Thus you'll be able to use any type as a time value:



        [DebuggerDisplay("{Start} .. {End}")]
        public sealed class Meeting<T>
        where T : IComparable<T>
        {
        // You can replace these readonly fields with the auto-properties { get; private set; }:
        public readonly T Start;
        public readonly T End;

        public Meeting(T start, T end)
        {
        Start = start;
        End = end;
        }
        }


        Next you need a comparer:



        public sealed class MeetingComparer<T> : IEqualityComparer<Meeting<T>>
        where T : IComparable<T>
        {
        public bool Equals(Meeting<T> x, Meeting<T> y)
        {
        // We can use only 2 sequential comparisons to check for the intersection:
        return x.Start.CompareTo(y.Start) >= 0
        ? x.Start.CompareTo(y.End) <= 0
        : y.Start.CompareTo(x.End) <= 0;
        }

        public int GetHashCode(Meeting<T> obj)
        {
        // Make all meetings have the same hash code.
        // In this case the Equals method will be called for each object.
        return 1;
        }
        }


        And finally you could use LINQ to find the intersecting meetings:



        private static IEnumerable<Meeting<T>> FindIntersections<T>(IEnumerable<Meeting<T>> list1,
        IEnumerable<Meeting<T>> list2)
        where T : IComparable<T>
        {
        return list1.Join(list2, p => p, p => p,
        (a, b) => new { a, b }, new MeetingComparer<T>())
        .SelectMany(p => p);
        }


        Sample:



        var list1 = new List<Meeting<int>>
        {
        new Meeting<int>(0, 1),
        new Meeting<int>(100, 111),
        new Meeting<int>(20, 41),
        new Meeting<int>(10, 11)
        };
        var list2 = new List<Meeting<int>>
        {
        new Meeting<int>(2, 3),
        new Meeting<int>(105, 106),
        new Meeting<int>(40, 41),
        new Meeting<int>(15, 16)
        };

        var intersection = FindIntersections(list1, list2);


        EDIT

        Try this code to find intersections of the sorted sets. It has complexity $O(N+M)$:



        private static IEnumerable<Meeting<T>> FindIntersections<T>(IEnumerable<Meeting<T>> listX,
        IEnumerable<Meeting<T>> listY)
        where T : IComparable<T>
        {
        var iteratorX = listX.GetEnumerator();
        var iteratorY = listY.GetEnumerator();
        Meeting<T> lastX = null;
        Meeting<T> lastY = null;
        iteratorX.MoveNext();
        iteratorY.MoveNext();
        while (iteratorX.Current != null && iteratorY.Current != null)
        {
        Meeting<T> x = iteratorX.Current;
        Meeting<T> y = iteratorY.Current;

        // Move iterators if needed:
        if (x.End.CompareTo(y.Start) < 0)
        {
        iteratorX.MoveNext();
        continue;
        }
        if (y.End.CompareTo(x.Start) < 0)
        {
        iteratorY.MoveNext();
        continue;
        }

        // Add items to the resulting set, if the items aren't already there:
        if (lastX != x)
        {
        yield return x;
        lastX = x;
        }
        if (lastY != y)
        {
        yield return y;
        lastY = y;
        }

        // Determine which iterator should be moved first:
        if (y.End.CompareTo(x.End) >= 0)
        {
        iteratorX.MoveNext();
        }
        else
        {
        iteratorY.MoveNext();
        }
        }
        }


        The method above:




        • Returns a set of the unique Meeting<T>s.

        • Supports case if one range overlaps several ranges in another set.






        share|improve this answer

























          up vote
          7
          down vote



          accepted







          up vote
          7
          down vote



          accepted






          You could make the Meeting class generic with the T : IComparable<T> constraint. Thus you'll be able to use any type as a time value:



          [DebuggerDisplay("{Start} .. {End}")]
          public sealed class Meeting<T>
          where T : IComparable<T>
          {
          // You can replace these readonly fields with the auto-properties { get; private set; }:
          public readonly T Start;
          public readonly T End;

          public Meeting(T start, T end)
          {
          Start = start;
          End = end;
          }
          }


          Next you need a comparer:



          public sealed class MeetingComparer<T> : IEqualityComparer<Meeting<T>>
          where T : IComparable<T>
          {
          public bool Equals(Meeting<T> x, Meeting<T> y)
          {
          // We can use only 2 sequential comparisons to check for the intersection:
          return x.Start.CompareTo(y.Start) >= 0
          ? x.Start.CompareTo(y.End) <= 0
          : y.Start.CompareTo(x.End) <= 0;
          }

          public int GetHashCode(Meeting<T> obj)
          {
          // Make all meetings have the same hash code.
          // In this case the Equals method will be called for each object.
          return 1;
          }
          }


          And finally you could use LINQ to find the intersecting meetings:



          private static IEnumerable<Meeting<T>> FindIntersections<T>(IEnumerable<Meeting<T>> list1,
          IEnumerable<Meeting<T>> list2)
          where T : IComparable<T>
          {
          return list1.Join(list2, p => p, p => p,
          (a, b) => new { a, b }, new MeetingComparer<T>())
          .SelectMany(p => p);
          }


          Sample:



          var list1 = new List<Meeting<int>>
          {
          new Meeting<int>(0, 1),
          new Meeting<int>(100, 111),
          new Meeting<int>(20, 41),
          new Meeting<int>(10, 11)
          };
          var list2 = new List<Meeting<int>>
          {
          new Meeting<int>(2, 3),
          new Meeting<int>(105, 106),
          new Meeting<int>(40, 41),
          new Meeting<int>(15, 16)
          };

          var intersection = FindIntersections(list1, list2);


          EDIT

          Try this code to find intersections of the sorted sets. It has complexity $O(N+M)$:



          private static IEnumerable<Meeting<T>> FindIntersections<T>(IEnumerable<Meeting<T>> listX,
          IEnumerable<Meeting<T>> listY)
          where T : IComparable<T>
          {
          var iteratorX = listX.GetEnumerator();
          var iteratorY = listY.GetEnumerator();
          Meeting<T> lastX = null;
          Meeting<T> lastY = null;
          iteratorX.MoveNext();
          iteratorY.MoveNext();
          while (iteratorX.Current != null && iteratorY.Current != null)
          {
          Meeting<T> x = iteratorX.Current;
          Meeting<T> y = iteratorY.Current;

          // Move iterators if needed:
          if (x.End.CompareTo(y.Start) < 0)
          {
          iteratorX.MoveNext();
          continue;
          }
          if (y.End.CompareTo(x.Start) < 0)
          {
          iteratorY.MoveNext();
          continue;
          }

          // Add items to the resulting set, if the items aren't already there:
          if (lastX != x)
          {
          yield return x;
          lastX = x;
          }
          if (lastY != y)
          {
          yield return y;
          lastY = y;
          }

          // Determine which iterator should be moved first:
          if (y.End.CompareTo(x.End) >= 0)
          {
          iteratorX.MoveNext();
          }
          else
          {
          iteratorY.MoveNext();
          }
          }
          }


          The method above:




          • Returns a set of the unique Meeting<T>s.

          • Supports case if one range overlaps several ranges in another set.






          share|improve this answer














          You could make the Meeting class generic with the T : IComparable<T> constraint. Thus you'll be able to use any type as a time value:



          [DebuggerDisplay("{Start} .. {End}")]
          public sealed class Meeting<T>
          where T : IComparable<T>
          {
          // You can replace these readonly fields with the auto-properties { get; private set; }:
          public readonly T Start;
          public readonly T End;

          public Meeting(T start, T end)
          {
          Start = start;
          End = end;
          }
          }


          Next you need a comparer:



          public sealed class MeetingComparer<T> : IEqualityComparer<Meeting<T>>
          where T : IComparable<T>
          {
          public bool Equals(Meeting<T> x, Meeting<T> y)
          {
          // We can use only 2 sequential comparisons to check for the intersection:
          return x.Start.CompareTo(y.Start) >= 0
          ? x.Start.CompareTo(y.End) <= 0
          : y.Start.CompareTo(x.End) <= 0;
          }

          public int GetHashCode(Meeting<T> obj)
          {
          // Make all meetings have the same hash code.
          // In this case the Equals method will be called for each object.
          return 1;
          }
          }


          And finally you could use LINQ to find the intersecting meetings:



          private static IEnumerable<Meeting<T>> FindIntersections<T>(IEnumerable<Meeting<T>> list1,
          IEnumerable<Meeting<T>> list2)
          where T : IComparable<T>
          {
          return list1.Join(list2, p => p, p => p,
          (a, b) => new { a, b }, new MeetingComparer<T>())
          .SelectMany(p => p);
          }


          Sample:



          var list1 = new List<Meeting<int>>
          {
          new Meeting<int>(0, 1),
          new Meeting<int>(100, 111),
          new Meeting<int>(20, 41),
          new Meeting<int>(10, 11)
          };
          var list2 = new List<Meeting<int>>
          {
          new Meeting<int>(2, 3),
          new Meeting<int>(105, 106),
          new Meeting<int>(40, 41),
          new Meeting<int>(15, 16)
          };

          var intersection = FindIntersections(list1, list2);


          EDIT

          Try this code to find intersections of the sorted sets. It has complexity $O(N+M)$:



          private static IEnumerable<Meeting<T>> FindIntersections<T>(IEnumerable<Meeting<T>> listX,
          IEnumerable<Meeting<T>> listY)
          where T : IComparable<T>
          {
          var iteratorX = listX.GetEnumerator();
          var iteratorY = listY.GetEnumerator();
          Meeting<T> lastX = null;
          Meeting<T> lastY = null;
          iteratorX.MoveNext();
          iteratorY.MoveNext();
          while (iteratorX.Current != null && iteratorY.Current != null)
          {
          Meeting<T> x = iteratorX.Current;
          Meeting<T> y = iteratorY.Current;

          // Move iterators if needed:
          if (x.End.CompareTo(y.Start) < 0)
          {
          iteratorX.MoveNext();
          continue;
          }
          if (y.End.CompareTo(x.Start) < 0)
          {
          iteratorY.MoveNext();
          continue;
          }

          // Add items to the resulting set, if the items aren't already there:
          if (lastX != x)
          {
          yield return x;
          lastX = x;
          }
          if (lastY != y)
          {
          yield return y;
          lastY = y;
          }

          // Determine which iterator should be moved first:
          if (y.End.CompareTo(x.End) >= 0)
          {
          iteratorX.MoveNext();
          }
          else
          {
          iteratorY.MoveNext();
          }
          }
          }


          The method above:




          • Returns a set of the unique Meeting<T>s.

          • Supports case if one range overlaps several ranges in another set.







          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Dec 7 '14 at 0:23

























          answered Dec 6 '14 at 22:07









          Dmitry

          4,36811129




          4,36811129
























              up vote
              7
              down vote













              Your intersection code only catches cases where a meeting is entirely within the time of another meeting. For example, it will not catch the overlap in 10am-2pm and 1pm-4pm. Instead, its easier to check for non-intersection, and then negate. This is a popular approach to checking for intersection in rectangles.



              if (!(item.StartTime > other.endTime || item.endTime < other.StartTime))  {
              // overlap
              }


              As others have mentioned the algorithmic improvement is to use a merge to get O(M + N) complexity. The tricky part is that you compare the ends of the meeting times to decide which to advance.



              Imagine one list with 1 all day meeting and the other with meetings every hour. The first overlaps works just fine, but the all day meeting started first and if you advance that list your search is ended prematurely.



              If you advance the list which has the earlier ending meeting you will be fine since that meeting ends before the other list's next item starts, you won't miss any overlaps.



              int meet1 = 0;
              int meet2 = 0;

              while (meet1 < list1.Count && meet2 < list2.Count) {
              if (intersects(list1[meet1], list2[meet2]) {
              // add to list
              }
              if (list1[meet1].endTime < list2[meet2].endTime) {
              ++meet1;
              } else {
              ++meet2;
              }
              }


              (feel free to edit and flesh this out)






              share|improve this answer























              • (item.StartTime > other.endTime || other.endTime < item.StartTime) is the same question twice
                – Ryan Heitner
                Dec 1 at 17:27










              • @RyanHeitner fixed
                – ryanpattison
                9 mins ago















              up vote
              7
              down vote













              Your intersection code only catches cases where a meeting is entirely within the time of another meeting. For example, it will not catch the overlap in 10am-2pm and 1pm-4pm. Instead, its easier to check for non-intersection, and then negate. This is a popular approach to checking for intersection in rectangles.



              if (!(item.StartTime > other.endTime || item.endTime < other.StartTime))  {
              // overlap
              }


              As others have mentioned the algorithmic improvement is to use a merge to get O(M + N) complexity. The tricky part is that you compare the ends of the meeting times to decide which to advance.



              Imagine one list with 1 all day meeting and the other with meetings every hour. The first overlaps works just fine, but the all day meeting started first and if you advance that list your search is ended prematurely.



              If you advance the list which has the earlier ending meeting you will be fine since that meeting ends before the other list's next item starts, you won't miss any overlaps.



              int meet1 = 0;
              int meet2 = 0;

              while (meet1 < list1.Count && meet2 < list2.Count) {
              if (intersects(list1[meet1], list2[meet2]) {
              // add to list
              }
              if (list1[meet1].endTime < list2[meet2].endTime) {
              ++meet1;
              } else {
              ++meet2;
              }
              }


              (feel free to edit and flesh this out)






              share|improve this answer























              • (item.StartTime > other.endTime || other.endTime < item.StartTime) is the same question twice
                – Ryan Heitner
                Dec 1 at 17:27










              • @RyanHeitner fixed
                – ryanpattison
                9 mins ago













              up vote
              7
              down vote










              up vote
              7
              down vote









              Your intersection code only catches cases where a meeting is entirely within the time of another meeting. For example, it will not catch the overlap in 10am-2pm and 1pm-4pm. Instead, its easier to check for non-intersection, and then negate. This is a popular approach to checking for intersection in rectangles.



              if (!(item.StartTime > other.endTime || item.endTime < other.StartTime))  {
              // overlap
              }


              As others have mentioned the algorithmic improvement is to use a merge to get O(M + N) complexity. The tricky part is that you compare the ends of the meeting times to decide which to advance.



              Imagine one list with 1 all day meeting and the other with meetings every hour. The first overlaps works just fine, but the all day meeting started first and if you advance that list your search is ended prematurely.



              If you advance the list which has the earlier ending meeting you will be fine since that meeting ends before the other list's next item starts, you won't miss any overlaps.



              int meet1 = 0;
              int meet2 = 0;

              while (meet1 < list1.Count && meet2 < list2.Count) {
              if (intersects(list1[meet1], list2[meet2]) {
              // add to list
              }
              if (list1[meet1].endTime < list2[meet2].endTime) {
              ++meet1;
              } else {
              ++meet2;
              }
              }


              (feel free to edit and flesh this out)






              share|improve this answer














              Your intersection code only catches cases where a meeting is entirely within the time of another meeting. For example, it will not catch the overlap in 10am-2pm and 1pm-4pm. Instead, its easier to check for non-intersection, and then negate. This is a popular approach to checking for intersection in rectangles.



              if (!(item.StartTime > other.endTime || item.endTime < other.StartTime))  {
              // overlap
              }


              As others have mentioned the algorithmic improvement is to use a merge to get O(M + N) complexity. The tricky part is that you compare the ends of the meeting times to decide which to advance.



              Imagine one list with 1 all day meeting and the other with meetings every hour. The first overlaps works just fine, but the all day meeting started first and if you advance that list your search is ended prematurely.



              If you advance the list which has the earlier ending meeting you will be fine since that meeting ends before the other list's next item starts, you won't miss any overlaps.



              int meet1 = 0;
              int meet2 = 0;

              while (meet1 < list1.Count && meet2 < list2.Count) {
              if (intersects(list1[meet1], list2[meet2]) {
              // add to list
              }
              if (list1[meet1].endTime < list2[meet2].endTime) {
              ++meet1;
              } else {
              ++meet2;
              }
              }


              (feel free to edit and flesh this out)







              share|improve this answer














              share|improve this answer



              share|improve this answer








              edited 10 mins ago

























              answered Dec 7 '14 at 16:14









              ryanpattison

              1706




              1706












              • (item.StartTime > other.endTime || other.endTime < item.StartTime) is the same question twice
                – Ryan Heitner
                Dec 1 at 17:27










              • @RyanHeitner fixed
                – ryanpattison
                9 mins ago


















              • (item.StartTime > other.endTime || other.endTime < item.StartTime) is the same question twice
                – Ryan Heitner
                Dec 1 at 17:27










              • @RyanHeitner fixed
                – ryanpattison
                9 mins ago
















              (item.StartTime > other.endTime || other.endTime < item.StartTime) is the same question twice
              – Ryan Heitner
              Dec 1 at 17:27




              (item.StartTime > other.endTime || other.endTime < item.StartTime) is the same question twice
              – Ryan Heitner
              Dec 1 at 17:27












              @RyanHeitner fixed
              – ryanpattison
              9 mins ago




              @RyanHeitner fixed
              – ryanpattison
              9 mins ago










              up vote
              5
              down vote













              If you don't count the "sorting of the lists" itself, you can iterate through both lists at the same time in a loop (while, not foreach) and only once which would be O(M+N) or even less: O(M+N) is a maximum, for "good sets" it can go as low as O(M) or O(N) depending on overlaps (thanks for pointing that out in the comments)



              It's too late here for a complete code, but here's a rundown with some pseudocode (comparison methods) to show the algorithm I would use... (EDIT2: Updated the comparison and validated it against several overlapping scenarios. The "isBefore" was a bit sketchy - "end is before other end" should do the trick)



              I still don't think there is a much faster solution... LINQ might make it more "versatile" but certainly not "more efficient" IMHO - with all that method calling in between...



              index1 = 0;
              index2 = 0;

              // as soon as the first list is exhausted, there can be no more overlaps
              while (index1 < list1.Count && index2 < list2.Count)
              {
              // check for overlapping timeframe in either direction...
              if (list1[index1].StartTime < list2[index2].EndTime &&
              list1[index1].EndTime > list2[index2].StartTime)
              {
              // overlaps - do whatever...
              }

              // Advance the one list that has the "older" ending time,
              // doesn't matter whicht if both are equal.
              if (list1[index1].EndTime < list2[index2].EndTime)
              index1++;
              else
              index2++;
              }





              share|improve this answer























              • It actually will be O(min(m,n)) :)
                – sha
                Dec 7 '14 at 0:36






              • 1




                @sha Only one of index1 or index2 is incremented so in the worst case one list reaches the end and the other is just shy of its end. O(M + N).
                – ryanpattison
                Dec 7 '14 at 3:59












              • isBefore will miss some intersections. list1=[(2,3),(4,5)] list2=[(1,5)] would fail to find the overlap between (4,5) and (1,5).
                – ryanpattison
                Dec 7 '14 at 6:21










              • Interesting... I shall have to look into a more precise definition of that. I'm still certain it can be done by only going through the sorted lists once, as I did that before.
                – Roman Gruber
                Dec 10 '14 at 17:12















              up vote
              5
              down vote













              If you don't count the "sorting of the lists" itself, you can iterate through both lists at the same time in a loop (while, not foreach) and only once which would be O(M+N) or even less: O(M+N) is a maximum, for "good sets" it can go as low as O(M) or O(N) depending on overlaps (thanks for pointing that out in the comments)



              It's too late here for a complete code, but here's a rundown with some pseudocode (comparison methods) to show the algorithm I would use... (EDIT2: Updated the comparison and validated it against several overlapping scenarios. The "isBefore" was a bit sketchy - "end is before other end" should do the trick)



              I still don't think there is a much faster solution... LINQ might make it more "versatile" but certainly not "more efficient" IMHO - with all that method calling in between...



              index1 = 0;
              index2 = 0;

              // as soon as the first list is exhausted, there can be no more overlaps
              while (index1 < list1.Count && index2 < list2.Count)
              {
              // check for overlapping timeframe in either direction...
              if (list1[index1].StartTime < list2[index2].EndTime &&
              list1[index1].EndTime > list2[index2].StartTime)
              {
              // overlaps - do whatever...
              }

              // Advance the one list that has the "older" ending time,
              // doesn't matter whicht if both are equal.
              if (list1[index1].EndTime < list2[index2].EndTime)
              index1++;
              else
              index2++;
              }





              share|improve this answer























              • It actually will be O(min(m,n)) :)
                – sha
                Dec 7 '14 at 0:36






              • 1




                @sha Only one of index1 or index2 is incremented so in the worst case one list reaches the end and the other is just shy of its end. O(M + N).
                – ryanpattison
                Dec 7 '14 at 3:59












              • isBefore will miss some intersections. list1=[(2,3),(4,5)] list2=[(1,5)] would fail to find the overlap between (4,5) and (1,5).
                – ryanpattison
                Dec 7 '14 at 6:21










              • Interesting... I shall have to look into a more precise definition of that. I'm still certain it can be done by only going through the sorted lists once, as I did that before.
                – Roman Gruber
                Dec 10 '14 at 17:12













              up vote
              5
              down vote










              up vote
              5
              down vote









              If you don't count the "sorting of the lists" itself, you can iterate through both lists at the same time in a loop (while, not foreach) and only once which would be O(M+N) or even less: O(M+N) is a maximum, for "good sets" it can go as low as O(M) or O(N) depending on overlaps (thanks for pointing that out in the comments)



              It's too late here for a complete code, but here's a rundown with some pseudocode (comparison methods) to show the algorithm I would use... (EDIT2: Updated the comparison and validated it against several overlapping scenarios. The "isBefore" was a bit sketchy - "end is before other end" should do the trick)



              I still don't think there is a much faster solution... LINQ might make it more "versatile" but certainly not "more efficient" IMHO - with all that method calling in between...



              index1 = 0;
              index2 = 0;

              // as soon as the first list is exhausted, there can be no more overlaps
              while (index1 < list1.Count && index2 < list2.Count)
              {
              // check for overlapping timeframe in either direction...
              if (list1[index1].StartTime < list2[index2].EndTime &&
              list1[index1].EndTime > list2[index2].StartTime)
              {
              // overlaps - do whatever...
              }

              // Advance the one list that has the "older" ending time,
              // doesn't matter whicht if both are equal.
              if (list1[index1].EndTime < list2[index2].EndTime)
              index1++;
              else
              index2++;
              }





              share|improve this answer














              If you don't count the "sorting of the lists" itself, you can iterate through both lists at the same time in a loop (while, not foreach) and only once which would be O(M+N) or even less: O(M+N) is a maximum, for "good sets" it can go as low as O(M) or O(N) depending on overlaps (thanks for pointing that out in the comments)



              It's too late here for a complete code, but here's a rundown with some pseudocode (comparison methods) to show the algorithm I would use... (EDIT2: Updated the comparison and validated it against several overlapping scenarios. The "isBefore" was a bit sketchy - "end is before other end" should do the trick)



              I still don't think there is a much faster solution... LINQ might make it more "versatile" but certainly not "more efficient" IMHO - with all that method calling in between...



              index1 = 0;
              index2 = 0;

              // as soon as the first list is exhausted, there can be no more overlaps
              while (index1 < list1.Count && index2 < list2.Count)
              {
              // check for overlapping timeframe in either direction...
              if (list1[index1].StartTime < list2[index2].EndTime &&
              list1[index1].EndTime > list2[index2].StartTime)
              {
              // overlaps - do whatever...
              }

              // Advance the one list that has the "older" ending time,
              // doesn't matter whicht if both are equal.
              if (list1[index1].EndTime < list2[index2].EndTime)
              index1++;
              else
              index2++;
              }






              share|improve this answer














              share|improve this answer



              share|improve this answer








              edited Dec 10 '14 at 17:33

























              answered Dec 6 '14 at 23:26









              Roman Gruber

              1592




              1592












              • It actually will be O(min(m,n)) :)
                – sha
                Dec 7 '14 at 0:36






              • 1




                @sha Only one of index1 or index2 is incremented so in the worst case one list reaches the end and the other is just shy of its end. O(M + N).
                – ryanpattison
                Dec 7 '14 at 3:59












              • isBefore will miss some intersections. list1=[(2,3),(4,5)] list2=[(1,5)] would fail to find the overlap between (4,5) and (1,5).
                – ryanpattison
                Dec 7 '14 at 6:21










              • Interesting... I shall have to look into a more precise definition of that. I'm still certain it can be done by only going through the sorted lists once, as I did that before.
                – Roman Gruber
                Dec 10 '14 at 17:12


















              • It actually will be O(min(m,n)) :)
                – sha
                Dec 7 '14 at 0:36






              • 1




                @sha Only one of index1 or index2 is incremented so in the worst case one list reaches the end and the other is just shy of its end. O(M + N).
                – ryanpattison
                Dec 7 '14 at 3:59












              • isBefore will miss some intersections. list1=[(2,3),(4,5)] list2=[(1,5)] would fail to find the overlap between (4,5) and (1,5).
                – ryanpattison
                Dec 7 '14 at 6:21










              • Interesting... I shall have to look into a more precise definition of that. I'm still certain it can be done by only going through the sorted lists once, as I did that before.
                – Roman Gruber
                Dec 10 '14 at 17:12
















              It actually will be O(min(m,n)) :)
              – sha
              Dec 7 '14 at 0:36




              It actually will be O(min(m,n)) :)
              – sha
              Dec 7 '14 at 0:36




              1




              1




              @sha Only one of index1 or index2 is incremented so in the worst case one list reaches the end and the other is just shy of its end. O(M + N).
              – ryanpattison
              Dec 7 '14 at 3:59






              @sha Only one of index1 or index2 is incremented so in the worst case one list reaches the end and the other is just shy of its end. O(M + N).
              – ryanpattison
              Dec 7 '14 at 3:59














              isBefore will miss some intersections. list1=[(2,3),(4,5)] list2=[(1,5)] would fail to find the overlap between (4,5) and (1,5).
              – ryanpattison
              Dec 7 '14 at 6:21




              isBefore will miss some intersections. list1=[(2,3),(4,5)] list2=[(1,5)] would fail to find the overlap between (4,5) and (1,5).
              – ryanpattison
              Dec 7 '14 at 6:21












              Interesting... I shall have to look into a more precise definition of that. I'm still certain it can be done by only going through the sorted lists once, as I did that before.
              – Roman Gruber
              Dec 10 '14 at 17:12




              Interesting... I shall have to look into a more precise definition of that. I'm still certain it can be done by only going through the sorted lists once, as I did that before.
              – Roman Gruber
              Dec 10 '14 at 17:12










              up vote
              4
              down vote













              I would make the MeetingList simpler and take both conditions out of the if for better maintainability:



              public class IntersectingMeetings
              {
              public static List<Meeting> FindInterSections(MeetingList meetingList1, MeetingList meetingList2)
              {
              meetingList1.Sort();
              meetingList2.Sort();
              List<Meeting> intersectingList = new List<Meeting>();
              foreach (var first in meetingList1)
              {
              foreach (var second in meetingList2)
              {
              bool case1 = (first.StartTime >= second.StartTime && first.EndTime <= second.EndTime);
              bool case2 = (second.StartTime >= first.StartTime && second.EndTime <= first.EndTime);

              if (case1 || case2)
              {
              intersectingList.Add(first);
              intersectingList.Add(second);
              }
              }
              }
              return intersectingList;
              }
              }


              public class MeetingList : List<Meeting>
              {
              public void AddMeeting(int start, int end)
              {
              Add(new Meeting(start, end));
              }
              }





              share|improve this answer



























                up vote
                4
                down vote













                I would make the MeetingList simpler and take both conditions out of the if for better maintainability:



                public class IntersectingMeetings
                {
                public static List<Meeting> FindInterSections(MeetingList meetingList1, MeetingList meetingList2)
                {
                meetingList1.Sort();
                meetingList2.Sort();
                List<Meeting> intersectingList = new List<Meeting>();
                foreach (var first in meetingList1)
                {
                foreach (var second in meetingList2)
                {
                bool case1 = (first.StartTime >= second.StartTime && first.EndTime <= second.EndTime);
                bool case2 = (second.StartTime >= first.StartTime && second.EndTime <= first.EndTime);

                if (case1 || case2)
                {
                intersectingList.Add(first);
                intersectingList.Add(second);
                }
                }
                }
                return intersectingList;
                }
                }


                public class MeetingList : List<Meeting>
                {
                public void AddMeeting(int start, int end)
                {
                Add(new Meeting(start, end));
                }
                }





                share|improve this answer

























                  up vote
                  4
                  down vote










                  up vote
                  4
                  down vote









                  I would make the MeetingList simpler and take both conditions out of the if for better maintainability:



                  public class IntersectingMeetings
                  {
                  public static List<Meeting> FindInterSections(MeetingList meetingList1, MeetingList meetingList2)
                  {
                  meetingList1.Sort();
                  meetingList2.Sort();
                  List<Meeting> intersectingList = new List<Meeting>();
                  foreach (var first in meetingList1)
                  {
                  foreach (var second in meetingList2)
                  {
                  bool case1 = (first.StartTime >= second.StartTime && first.EndTime <= second.EndTime);
                  bool case2 = (second.StartTime >= first.StartTime && second.EndTime <= first.EndTime);

                  if (case1 || case2)
                  {
                  intersectingList.Add(first);
                  intersectingList.Add(second);
                  }
                  }
                  }
                  return intersectingList;
                  }
                  }


                  public class MeetingList : List<Meeting>
                  {
                  public void AddMeeting(int start, int end)
                  {
                  Add(new Meeting(start, end));
                  }
                  }





                  share|improve this answer














                  I would make the MeetingList simpler and take both conditions out of the if for better maintainability:



                  public class IntersectingMeetings
                  {
                  public static List<Meeting> FindInterSections(MeetingList meetingList1, MeetingList meetingList2)
                  {
                  meetingList1.Sort();
                  meetingList2.Sort();
                  List<Meeting> intersectingList = new List<Meeting>();
                  foreach (var first in meetingList1)
                  {
                  foreach (var second in meetingList2)
                  {
                  bool case1 = (first.StartTime >= second.StartTime && first.EndTime <= second.EndTime);
                  bool case2 = (second.StartTime >= first.StartTime && second.EndTime <= first.EndTime);

                  if (case1 || case2)
                  {
                  intersectingList.Add(first);
                  intersectingList.Add(second);
                  }
                  }
                  }
                  return intersectingList;
                  }
                  }


                  public class MeetingList : List<Meeting>
                  {
                  public void AddMeeting(int start, int end)
                  {
                  Add(new Meeting(start, end));
                  }
                  }






                  share|improve this answer














                  share|improve this answer



                  share|improve this answer








                  edited Dec 6 '14 at 22:58









                  ferada

                  9,1111554




                  9,1111554










                  answered Dec 6 '14 at 20:53









                  t3chb0t

                  33.8k746110




                  33.8k746110






























                      draft saved

                      draft discarded




















































                      Thanks for contributing an answer to Code Review Stack Exchange!


                      • Please be sure to answer the question. Provide details and share your research!

                      But avoid



                      • Asking for help, clarification, or responding to other answers.

                      • Making statements based on opinion; back them up with references or personal experience.


                      Use MathJax to format equations. MathJax reference.


                      To learn more, see our tips on writing great answers.





                      Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


                      Please pay close attention to the following guidance:


                      • Please be sure to answer the question. Provide details and share your research!

                      But avoid



                      • Asking for help, clarification, or responding to other answers.

                      • Making statements based on opinion; back them up with references or personal experience.


                      To learn more, see our tips on writing great answers.




                      draft saved


                      draft discarded














                      StackExchange.ready(
                      function () {
                      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f71896%2ffinding-overlapping-time-intervals%23new-answer', 'question_page');
                      }
                      );

                      Post as a guest















                      Required, but never shown





















































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown

































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown







                      Popular posts from this blog

                      Create new schema in PostgreSQL using DBeaver

                      Deepest pit of an array with Javascript: test on Codility

                      Costa Masnaga