Interval - How to Succeed in Algorithms Interview


Interval - How to Succeed in Algorithms Interview

How to Succeed in Algorithms Interview Series


Application of Interval

  • sort by start time or finish time
    • sort then choose greedily
    • sort then dynamic programming
    • track last max_end (or max_start)
  • Two pointers for input data: int[] start, end
  • TreeMap:
    • start -> end, start/end -> index
    • boundary count: point -> count
  • TreeSet: intervals, sort by start or end time
  • PriorityQueue
    • merge k sorted list: [outerIndex, innerIndex]
    • [point, isStart] or interval
  • Greedy
  • Boundary count: start +1, end -1;
    • with TreeMap

Implementation

  • List merged,
  • save prevInterval, lastEnd

Basic

  • LeetCode 57 - Insert Interval
    • 3 steps: add intervals before the inserted, merge, add intervals after the inserted
    public List<Interval> insert(List<Interval> intervals, Interval newInterval) {
      List<Interval> result = new LinkedList<>();
      int i = 0;
      // add all the intervals ending before newInterval starts
      while (i < intervals.size() && intervals.get(i).end < newInterval.start)
          result.add(intervals.get(i++));
      // merge all overlapping intervals to one considering newInterval
      while (i < intervals.size() && intervals.get(i).start <= newInterval.end) {
          newInterval = new Interval( // we could mutate newInterval here also
                  Math.min(newInterval.start, intervals.get(i).start),
                  Math.max(newInterval.end, intervals.get(i).end));
          i++;
      }
      result.add(newInterval); // add the union of intervals we got
      // add all the rest
      while (i < intervals.size()) result.add(intervals.get(i++));
      return result;
    }
  • LeetCode 56 - Merge Intervals
private class IntervalComparator implements Comparator<Interval> {
  @Override
  public int compare(Interval a, Interval b) {
    return a.start < b.start ? -1 : a.start == b.start ? 0 : 1;
  }
}
public List<Interval> merge(List<Interval> intervals) {
  Collections.sort(intervals, new IntervalComparator());
  LinkedList<Interval> merged = new LinkedList<Interval>();
  for (Interval interval : intervals) {
    if (merged.isEmpty() || merged.getLast().end < interval.start) {
      merged.add(interval);
    }
    else {
      merged.getLast().end = Math.max(merged.getLast().end, interval.end);
    }
  }
  return merged;
}
  • LeetCode 436 - Find Right Interval
    • TreeMap can simplify code related with binary search
    public int[] findRightInterval(Interval[] intervals) {
      int[] result = new int[intervals.length];
      java.util.NavigableMap<Integer, Integer> intervalMap = new TreeMap<>();
      for (int i = 0; i < intervals.length; ++i) {
          intervalMap.put(intervals[i].start, i);    
      }
      for (int i = 0; i < intervals.length; ++i) {
          Map.Entry<Integer, Integer> entry = intervalMap.ceilingEntry(intervals[i].end);
          result[i] = (entry != null) ? entry.getValue() : -1;
      }
      return result;
    }
  • LeetCode 253 - Meeting Rooms II
    public int minMeetingRooms(Interval[] intervals) {
      if (intervals == null || intervals.length == 0) {
          return 0;
      }
      TreeMap<Integer, Integer> times = new TreeMap<>();
      for (Interval i : intervals) {
          times.put(i.start, times.getOrDefault(i.start, 0) + 1);
          times.put(i.end, times.getOrDefault(i.end, 0) - 1);
      }
      int count = 0, res = 0;
      for (int c : times.values()) {
          count += c;
          res = Math.max(res, count);
      }
      return res;
    }

Convert events into start, end array

Sort

for (int i = 1; i < intervals.length; i++) {
  Interval a = intervals[i];
  if (a.getLow() <= high) {
    high = Math.max(a.getHigh(), high);
  } else {
    maxInterval = Math.max(maxInterval, high - low);
    maxGap = Math.max(maxGap, a.getLow() - high);
    low = a.getLow();
    high = a.getHigh();
  }
}

TreeMap

  • start -> end
  • boundary count, position -> count+1 for start, count-1 for end
Methods of TreeMap
  • floorKey, ceilingKey, lowerEntry,
LeetCode 729 - My Calendar I
List<int[]> calendar;
List<int[]> overlaps;

MyCalendarTwo() {
    calendar = new ArrayList();
}

public boolean book(int start, int end) {
    for (int[] iv: overlaps) {
        if (iv[0] < end && start < iv[1]) return false;
    }
    for (int[] iv: calendar) {
        if (iv[0] < end && start < iv[1])
            overlaps.add(new int[]{Math.max(start, iv[0]), Math.min(end, iv[1])});
    }
    calendar.add(new int[]{start, end});
    return true;
}
// -------
TreeMap<Integer, Integer> delta;

public MyCalendarTwo() {
    delta = new TreeMap();
}

public boolean book(int start, int end) {
    delta.put(start, delta.getOrDefault(start, 0) + 1);
    delta.put(end, delta.getOrDefault(end, 0) - 1);

    int active = 0;
    for (int d: delta.values()) {
        active += d;
        if (active >= 3) {
            delta.put(start, delta.get(start) - 1);
            delta.put(end, delta.get(end) + 1);
            if (delta.get(start) == 0)
                delta.remove(start);
            return false;
        }
    }
    return true;
}
LeetCode 732 - My Calendar III
  • boundary count
LeetCode 352. Data Stream as Disjoint Intervals
  • TreeMap: start -> Interval
LeetCode 715 - Range Module

Boundary count

  • boundary count, position -> count+1 for start, count-1 for end
  • critical point: cnt=0 or cnt itself
  • sort, TreeMap or PriorityQueue

PriorityQueue

public List<Interval> employeeFreeTime(List<List<Interval>> schedule) {
  List<Interval> res = new ArrayList<Interval>();
  PriorityQueue<Node> minHeap = new PriorityQueue<Node>(
      (a, b) -> schedule.get(a.employee).get(a.index).start - schedule.get(b.employee).get(b.index).start);

  int start = Integer.MAX_VALUE;
  for (int i = 0; i < schedule.size(); i++) {
    minHeap.add(new Node(i, 0));
    start = Math.min(start, schedule.get(i).get(0).start);
  }

  while (!minHeap.isEmpty()) {
    Node cur = minHeap.poll();
    if (start < schedule.get(cur.employee).get(cur.index).start) {
      res.add(new Interval(start, schedule.get(cur.employee).get(cur.index).start));
    }

    start = Math.max(start, schedule.get(cur.employee).get(cur.index).end);
    cur.index++;
    if (cur.index < schedule.get(cur.employee).size()) {
      minHeap.add(cur);
    }
  }
  return res;
}

class Node {
  int employee;
  int index;

  public Node(int employee, int index) {
    this.employee = employee;
    this.index = index;
  }
}

Greedy

Interval Tree

Labels

adsense (5) Algorithm (69) Algorithm Series (35) Android (7) ANT (6) bat (8) Big Data (7) Blogger (14) Bugs (6) Cache (5) Chrome (19) Code Example (29) Code Quality (7) Coding Skills (5) Database (7) Debug (16) Design (5) Dev Tips (63) Eclipse (32) Git (5) Google (33) Guava (7) How to (9) Http Client (8) IDE (7) Interview (88) J2EE (13) J2SE (49) Java (186) JavaScript (27) JSON (7) Learning code (9) Lesson Learned (6) Linux (26) Lucene-Solr (112) Mac (10) Maven (8) Network (9) Nutch2 (18) Performance (9) PowerShell (11) Problem Solving (11) Programmer Skills (6) regex (5) Scala (6) Security (9) Soft Skills (38) Spring (22) System Design (11) Testing (7) Text Mining (14) Tips (17) Tools (24) Troubleshooting (29) UIMA (9) Web Development (19) Windows (21) xml (5)