|
package com.samsara; |
|
|
|
import java.util.ArrayList; |
|
import java.util.Arrays; |
|
import java.util.List; |
|
import org.junit.Assert; |
|
import org.junit.Test; |
|
|
|
public class FindAlertRanges { |
|
|
|
static class Interval { |
|
|
|
public final int timestamp; |
|
public final int value; |
|
|
|
public Interval(int timestamp, int value) { |
|
this.timestamp = timestamp; |
|
this.value = value; |
|
} |
|
|
|
@Override |
|
public String toString() { |
|
return String.format("(timestamp=%d, value=%d)", this.timestamp, this.value); |
|
} |
|
} |
|
|
|
static class Pair { |
|
private final int left; |
|
private final int right; |
|
|
|
public Pair(int left, int right) { |
|
this.left = left; |
|
this.right = right; |
|
} |
|
|
|
@Override |
|
public boolean equals(Object obj) { |
|
if (!(obj instanceof Pair)) { |
|
return false; |
|
} |
|
Pair other = (Pair) obj; |
|
return this.left == other.left && this.right == other.right; |
|
} |
|
|
|
@Override |
|
public String toString() { |
|
return String.format("(%d, %d)", this.left, this.right); |
|
} |
|
} |
|
|
|
private static final int INFINITY = Integer.MIN_VALUE; |
|
|
|
public static List<Pair> findAlertRanges(List<Interval> list, int threshold) { |
|
List<Interval> intervals = new ArrayList<>() {{ |
|
addAll(list); |
|
// TRICK: add sentinel |
|
add(new Interval(INFINITY, INFINITY)); |
|
}}; |
|
|
|
List<Pair> ranges = new ArrayList<>(); |
|
for (int i = 0, j = i + 1; j < intervals.size(); i++, j++) { |
|
Interval a = intervals.get(i); |
|
Interval b = intervals.get(j); |
|
|
|
if (a.value < threshold) { |
|
continue; |
|
} |
|
|
|
Pair current = null; |
|
if (a.value >= threshold) { |
|
current = new Pair(a.timestamp, INFINITY); |
|
i--; |
|
} |
|
|
|
if (current != null && b.value < threshold) { |
|
ranges.add(new Pair(current.left, b.timestamp)); |
|
i = j; |
|
j = i + 1; |
|
} |
|
} |
|
|
|
if (ranges.isEmpty()) { |
|
return Arrays.asList(new Pair(INFINITY, INFINITY)); |
|
} |
|
return ranges; |
|
} |
|
|
|
@Test |
|
public void testUpperboundA() { |
|
Pair[] expected = new Pair[]{new Pair(1, INFINITY)}; |
|
Pair[] actual = testRange(Arrays.asList( |
|
new Interval(1, 40), |
|
new Interval(2, 40) |
|
), 40); |
|
Assert.assertArrayEquals(expected, actual); |
|
} |
|
|
|
@Test |
|
public void testUpperboundB() { |
|
Pair[] expected = new Pair[]{new Pair(1, INFINITY)}; |
|
Pair[] actual = testRange(Arrays.asList( |
|
new Interval(0, 0), |
|
new Interval(1, 40) |
|
), 40); |
|
Assert.assertArrayEquals(expected, actual); |
|
} |
|
|
|
@Test |
|
public void testEmpty() { |
|
Pair[] expected = new Pair[]{new Pair(INFINITY, INFINITY)}; |
|
Pair[] actual = testRange(Arrays.asList( |
|
new Interval(1, 39), |
|
new Interval(2, 20) |
|
), 40); |
|
Assert.assertArrayEquals(expected, actual); |
|
} |
|
|
|
@Test |
|
public void testMultipleBounded() { |
|
Pair[] expected = new Pair[]{ |
|
new Pair(1, 2), |
|
new Pair(3, 4) |
|
}; |
|
Pair[] actual = testRange(Arrays.asList( |
|
new Interval(1, 40), |
|
new Interval(2, 0), |
|
new Interval(3, 40), |
|
new Interval(4, 0) |
|
), 40); |
|
Assert.assertArrayEquals(expected, actual); |
|
} |
|
|
|
@Test |
|
public void testSinglePair() { |
|
Pair[] expected = new Pair[]{new Pair(1, 3)}; |
|
Pair[] actual = testRange(Arrays.asList( |
|
new Interval(1, 40), |
|
new Interval(2, 40), |
|
new Interval(3, 0) |
|
), 40); |
|
Assert.assertArrayEquals(expected, actual); |
|
} |
|
|
|
@Test |
|
public void testSingleIntervalA() { |
|
Pair[] expected = new Pair[]{new Pair(1, INFINITY)}; |
|
Pair[] actual = testRange(Arrays.asList( |
|
new Interval(1, 40) |
|
), 40); |
|
Assert.assertArrayEquals(expected, actual); |
|
} |
|
|
|
@Test |
|
public void testSingleIntervalB() { |
|
Pair[] expected = new Pair[]{new Pair(INFINITY, INFINITY)}; |
|
Pair[] actual = testRange(Arrays.asList( |
|
new Interval(1, 39) |
|
), 40); |
|
Assert.assertArrayEquals(expected, actual); |
|
} |
|
|
|
@Test |
|
public void testMultipleUnbounded() { |
|
Pair[] expected = new Pair[]{ |
|
new Pair(1, 2), |
|
new Pair(4, INFINITY) |
|
}; |
|
Pair[] actual = testRange(Arrays.asList( |
|
new Interval(1, 40), |
|
new Interval(2, 0), |
|
new Interval(3, 0), |
|
new Interval(4, 40) |
|
), 40); |
|
Assert.assertArrayEquals(expected, actual); |
|
} |
|
|
|
private static Pair[] testRange(List<Interval> intervals, int threshold) { |
|
return findAlertRanges(intervals, threshold).toArray(new Pair[0]); |
|
} |
|
} |