Given a data stream input of non-negative integers a1, a2, ..., an, ..., summarize the numbers seen so far as a list of disjoint intervals.
For example, suppose the integers from the data stream are 1, 3, 7, 2, 6, ..., then the summary will be:
[1, 1] [1, 1], [3, 3] [1, 1], [3, 3], [7, 7] [1, 3], [7, 7] [1, 3], [6, 7]
Follow up:
What if there are lots of merges and the number of disjoint intervals are small compared to the data stream's size?
Credits:
Special thanks to @yunhong for adding this problem and creating most of the test cases.
Solution 1:
1 /** 2 * Definition for an interval. 3 * public class Interval { 4 * int start; 5 * int end; 6 * Interval() { start = 0; end = 0; } 7 * Interval(int s, int e) { start = s; end = e; } 8 * } 9 */ 10 public class SummaryRanges { 11 12 /** Initialize your data structure here. */ 13 public SummaryRanges() { 14 startMap = new HashMap<Integer, Interval>(); 15 endMap = new HashMap<Integer, Interval>(); 16 addedNum = new HashSet<Integer>(); 17 } 18 19 public void addNum(int val) { 20 if (addedNum.contains(val)) return; 21 22 Interval pre = null, after = null; 23 if (endMap.containsKey(val - 1)) 24 pre = endMap.get(val - 1); 25 if (startMap.containsKey(val + 1)) 26 after = startMap.get(val + 1); 27 28 if (pre != null && after != null) { 29 endMap.remove(after.end); 30 startMap.remove(after.start); 31 endMap.remove(pre.end); 32 pre.end = after.end; 33 endMap.put(pre.end, pre); 34 } else if (pre != null) { 35 endMap.remove(pre.end); 36 pre.end = val; 37 endMap.put(val, pre); 38 } else if (after != null) { 39 startMap.remove(after.start); 40 after.start = val; 41 startMap.put(val, after); 42 } else { 43 Interval single = new Interval(val, val); 44 endMap.put(val, single); 45 startMap.put(val, single); 46 } 47 48 addedNum.add(val); 49 } 50 51 public List<Interval> getIntervals() { 52 List<Interval> intervalList = new ArrayList<Interval>(endMap.values()); 53 Collections.sort(intervalList, new Comparator<Interval>() { 54 public int compare(Interval v1, Interval v2) { 55 return v1.start - v2.start; 56 } 57 }); 58 return intervalList; 59 } 60 61 HashMap<Integer, Interval> startMap; 62 HashMap<Integer, Interval> endMap; 63 HashSet<Integer> addedNum; 64 } 65 66 /** 67 * Your SummaryRanges object will be instantiated and called as such: 68 * SummaryRanges obj = new SummaryRanges(); 69 * obj.addNum(val); 70 * List<Interval> param_2 = obj.getIntervals(); 71 */
This solution introduces many redundant: To find the "pre", we only need to find the interval with the largest start that is less than val. In short, we only need to compare Interval.start
Solution 2:
1 /** 2 * Definition for an interval. 3 * public class Interval { 4 * int start; 5 * int end; 6 * Interval() { start = 0; end = 0; } 7 * Interval(int s, int e) { start = s; end = e; } 8 * } 9 */ 10 public class SummaryRanges { 11 12 /** Initialize your data structure here. */ 13 public SummaryRanges() { 14 itvlSet = new TreeSet<Interval>(new Comparator<Interval>(){ 15 public int compare(Interval v1, Interval v2){ 16 return v1.start-v2.start; 17 } 18 }); 19 20 } 21 22 public void addNum(int val) { 23 Interval itvl = new Interval(val,val); 24 Interval pre = itvlSet.floor(itvl); 25 Interval after = itvlSet.ceiling(itvl); 26 27 if ( (pre!=null && pre.end >= val) || (after!=null && after.start <=val)) return; 28 29 if (pre!=null && pre.end==val-1){ 30 itvlSet.remove(pre); 31 itvl.start = pre.start; 32 } 33 if (after!=null && after.start==val+1){ 34 itvlSet.remove(after); 35 itvl.end = after.end; 36 } 37 itvlSet.add(itvl); 38 } 39 40 public List<Interval> getIntervals() { 41 return new ArrayList<Interval>(itvlSet); 42 43 } 44 45 TreeSet<Interval> itvlSet; 46 } 47 48 /** 49 * Your SummaryRanges object will be instantiated and called as such: 50 * SummaryRanges obj = new SummaryRanges(); 51 * obj.addNum(val); 52 * List<Interval> param_2 = obj.getIntervals(); 53 */