package cw; import java.util.TreeSet; class Interval { private static class Range implements Comparable { private int from; private int to; public Range(int from, int to) { this.from = from; this.to = to; } public int length() { return to - from; } public Range merge(Range other) { return new Range(Math.min(from, other.from), Math.max(to, other.to)); } public boolean mergeInSitu(Range other) { if (!canMerge(other)) { return false; } from = Math.min(from, other.from); to = Math.max(to, other.to); return true; } public boolean has(int x) { return from <= x && x <= to; } public boolean isSubrangeOf(Range other) { return other.has(from) && other.has(to); } public boolean isPrefixOf(Range other) { return from <= other.from && other.has(to); } public boolean isSuffixOf(Range other) { return to >= other.to && has(other.from); } public boolean canMerge(Range other) { return isSubrangeOf(other) || isPrefixOf(other) || isSuffixOf(other); } @Override public int compareTo(Range other) { if (other == null) { throw new NullPointerException(); } if (from == other.from && to == other.to) { return 0; } if (to < other.from || from < other.from) { return -1; } return 1; } } private static void insertRange(TreeSet ranges, Range range) { for (Range r : ranges) { if (r.canMerge(range)) { ranges.remove(r); ranges.add(r.merge(range)); return; } } ranges.add(range); } private static boolean mergeRanges(TreeSet ranges) { for (Range x : ranges) { for (Range y : ranges) { if (x == y) { continue; } if (x.canMerge(y)) { ranges.remove(x); ranges.remove(y); ranges.add(x.merge(y)); return true; } } } return false; } public static int sumIntervals(int[][] intervals) { if (intervals == null) { return 0; } TreeSet ranges = new TreeSet<>(); // Go through the intervals and construct a set out of them // when adding each interval, try to merge it in-situ with any of the // existing intervals for (int[] interval : intervals) { insertRange(ranges, new Range(interval[0], interval[1])); } // then iteratively merge the set of intervals while possible boolean hasChanged = true; while (hasChanged) { hasChanged = mergeRanges(ranges); } for (Range r : ranges) { System.out.format("%d, %d; ", r.from, r.to); } System.out.println(); return ranges.stream().map(Range::length).reduce(Integer::sum).orElse(0); } public static void main(String[] args) { // null argument System.out.format("%d == %d\n", Interval.sumIntervals(null), 0); // => 0 // empty intervals System.out.format("%d == %d\n", Interval.sumIntervals(new int[][]{}), 0); // => 0 System.out.format("%d == %d\n", Interval.sumIntervals(new int[][]{{2,2}, {5,5}}), 0); // => 0 // disjoined intervals System.out.format("%d == %d\n", Interval.sumIntervals(new int[][]{ {1,2},{3,5} }), 3); // => (2-1) + (5-3) = 3 // overlapping intervals System.out.format("%d == %d\n", Interval.sumIntervals(new int[][]{ {1,4},{3,6},{2,8} }), 7); // [1,8] => 7 } }