package com.interview.misc;
/**
* Date 04/28/2016
* @author Tushar Roy
*
* Find range minimum query using sparse table.
*
* Preprocessing Time complexity O(nlogn)
* Query Time complexity O(1)
* Space complexity O(nlogn)
*
* Reference -
* https://www.topcoder.com/community/data-science/data-science-tutorials/range-minimum-query-and-lowest-common-ancestor/
*/
public class SparseTableRangeMinimumQuery {
private final int[][] sparse;
private final int n;
private final int[] input;
public SparseTableRangeMinimumQuery(int[] input) {
this.input = input;
this.n = input.length;
this.sparse = preprocess(input, this.n);
}
private int[][] preprocess(int[] input, int n) {
int[][] sparse = new int[n][log2(n) + 1];
for (int i = 0; i < input.length; i++) {
sparse[i][0] = i;
}
for (int j = 1; 1 << j <= n; j++) {
for (int i = 0; i + (1 << j) - 1 < n; i++) {
if (input[sparse[i][j - 1]] < input[sparse[i + (1 << (j - 1))][j - 1]]) {
sparse[i][j] = sparse[i][j - 1];
} else {
sparse[i][j] = sparse[i + (1 << (j - 1))][j - 1];
}
}
}
return sparse;
}
public int rangeMinimumQuery(int low, int high) {
int l = high - low + 1;
int k = log2(l);
if (input[sparse[low][k]] <= input[sparse[low + l - (1<<k)][k]]) {
return input[sparse[low][k]];
} else {
return input[sparse[high - (1<<k) + 1][k]];
}
}
private static int log2(int n){
if(n <= 0) throw new IllegalArgumentException();
return 31 - Integer.numberOfLeadingZeros(n);
}
public static void main(String args[]) {
int[] input = {2, 5, 3, 6, 4, 1, -1, 3, 4, 2};
SparseTableRangeMinimumQuery sparseTableRangeMinimumQuery = new SparseTableRangeMinimumQuery(input);
for (int i = 0; i < input.length; i++) {
for (int j = i; j < input.length; j++) {
System.out.print(sparseTableRangeMinimumQuery.rangeMinimumQuery(i, j) + " ");
}
System.out.println();
}
}
}