mirror of
https://gitlab.com/mfocko/CodeWars.git
synced 2024-11-09 19:19:07 +01:00
149 lines
4 KiB
Java
149 lines
4 KiB
Java
|
package cw;
|
||
|
|
||
|
import java.util.TreeSet;
|
||
|
|
||
|
class Interval {
|
||
|
private static class Range implements Comparable<Range> {
|
||
|
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<Range> 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<Range> 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<Range> 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
|
||
|
}
|
||
|
}
|