1
0
Fork 0
mirror of https://gitlab.com/mfocko/CodeWars.git synced 2024-09-16 20:56:57 +02:00
CodeWars/4kyu/sum_of_intervals/solution.java
Matej Focko f5df67ce62
4kyu: add „Sum of Intervals“
Signed-off-by: Matej Focko <mfocko@redhat.com>
2022-08-07 15:55:50 +02:00

148 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
}
}