So I have the following algorithm. Given an array A[0 ... n - 1]
and the window length w
, compute all the windows A[0 ... w - 1], A[1 ... w], ..., A[n - w, n - 1]
, and for each window, in order, compute the maximum integer in the window, storing it in a result array:
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
public class Main {
private static final int[] EMPTY_INT_ARRAY = new int[0];
public static void main(String[] args) {
int[] array = {7, 86, 19, 5, 79, 28, 56, 8, 46, 63, 98, 65, 99};
int[] result = computeArrayWindowMaxima(array, 8);
System.out.println(Arrays.toString(array));
System.out.println(Arrays.toString(result));
System.out.println();
array = new int[]{1, 100, 2, 100, 4, 5, 6, 7};
result = computeArrayWindowMaxima(array, 4);
System.out.println(Arrays.toString(array));
System.out.println(Arrays.toString(result));
}
public static int[] computeArrayWindowMaxima(int[] array,
int windowLength) {
Objects.requireNonNull(array, "The input array is null.");
if (array.length == 0) {
return EMPTY_INT_ARRAY;
}
// Let n = array.length, m = windowLength.
windowLength = Math.min(windowLength, array.length);
int[] result = new int[array.length - windowLength + 1];
OrderStatisticTree<Integer> tree = new OrderStatisticTree<>();
Map<Integer, Integer> counterMap = new HashMap<>();
// Initialize the tree. Runs in O(m log m):
for (int i = 0; i < windowLength; ++i) {
tree.add(array[i]);
counterMap.put(array[i],
counterMap.getOrDefault(array[i], 0) + 1);
}
// Runs in O((n - m) log m).
for (int i = 0; i < result.length - 1; ++i) {
// Store tree window maximum. Runs in O(log m).
result[i] = tree.get(tree.size() - 1);
// Remove the int right before the current window. Runs in
// O(log m).
if (counterMap.getOrDefault(array[i], 0) < 2) {
counterMap.remove(array[i]);
tree.remove(array[i]);
} else {
counterMap.put(array[i], counterMap.get(array[i]) - 1);
}
// Add the int right after the current window. Runs in O(log m).
tree.add(array[windowLength + i]);
counterMap.put(array[windowLength + i],
counterMap.getOrDefault(
array[windowLength],
0)
+ 1);
}
result[result.length - 1] = tree.get(tree.size() - 1);
// Finally, we have O(m \log m) + O((n - m) log m) = O(n log m).
return result;
}
}
In the above procedure, tree
[1] holds the current window and the counterMap
is used to count the number of times each int
in the window occurs in that window. We need counterMap
since it is possible that multiple maximum ìnt
s belong to a window and removing one will "remove all duplicates", so to say.
Critique request
Now, what do you think? As always, tell me whatever comes to mind.
add(key)
,remove(key)
&maxKey()
fast is barking up the wrong tree. \$\endgroup\$