Open In App

Square Root (Sqrt) Decomposition Algorithm Using JavaScript Array

In this article, we are going to learn how we can use the Square Root (Sqrt) Decomposition Algorithm using a JavaScript array. The square Root Decomposition Technique is one of the most common query optimization techniques used by competitive programmers. This technique helps us to reduce Time Complexity by a factor of sqrt(N).

Approaches for Square Root (Sqrt) Decomposition Algorithm:



Square Root (Sqrt) Decomposition Algorithm Using Brute force

 

 



Example:




const MAXN = 20000;
const arr = [];
  
// Function for sqrt decomposition
function query(l, r) {
    let sum = 0;
    for (let i = l; i <= r; i++) {
        sum += arr[i];
    }
    return sum;
}
  
// Driver code
function main() {
    const input = [10, 9, 8, 7, 6, 5, 4, 3, 2, 1];
    const n = input.length;
  
    arr.push(...input);
  
    console.log("query(3,8) : ", query(3, 8));
    console.log("query(1,6) : ", query(1, 6));
    arr[5] = 0;
    console.log("query(6,6) : ", query(6, 6));
}
main();

Output
query(3,8) :  27
query(1,6) :  39
query(6,6) :  4

Time Complexity: O(N)

We can deal with these types of queries by summing the data from the completely 
overlapped decomposed blocks lying in the query range and then summing elements one
by one from the original array whose corresponding block is not completely overlapped by the query range.
So the answer for the above query in the described image will be: ans = 5 + 2 + 11 + 3 = 21

Efficient approach

Example:




let MAXN = 10000;
let SQRSIZE = 100;
  
let arr = new Array(MAXN);
for (let i = 0; i < MAXN; i++) {
    arr[i] = 0;
}
  
let block = new Array(SQRSIZE);
for (let i = 0; i < SQRSIZE; i++) {
    block[i] = 0;
}
  
let x;
  
// Function for updating value 
// at specific index
// of an array
function update(idx, val) {
    let blockNumber = idx / x;
    block[blockNumber] += val - arr[idx];
    arr[idx] = val;
}
function query(l, r) {
    let sum = 0;
    while (l < r && l % x != 0 && l != 0) {
        // traversing first block in range
        sum += arr[l];
        l++;
    }
    while (l + x - 1 <= r) {
      
        // Traversing completely
        // overlapped blocks in range
        sum += block[l / x];
        l += x;
    }
    while (l <= r) {
        // Traversing last block in range
        sum += arr[l];
        l++;
    }
    return sum;
}
  
// Fills values in input[]
function preprocess(input, n) {
  
    // Initiating block pointer
    let x = -1;
  
    // Calculating size of block
    x = Math.floor(Math.sqrt(n));
  
    // Building the decomposed array
    for (let i = 0; i < n; i++) {
        arr[i] = input[i];
        if (i % x == 0) {
  
            // Entering next block
            // Incrementing block pointer
            x++;
        }
        block[x] += arr[i];
    }
}
  
let input = [1, 5, 2, 4, 6, 1, 3, 5, 7, 10];
let n = input.length;
  
preprocess(input, n);
  
console.log("query(3,7) : " +
    query(3, 7));
console.log("query(4,4) : " +
    query(4, 4));
update(6, 0);
console.log("query(5,5) : " +
    query(5, 5));

Output
query(3,7) : 19
query(4,4) : 6
query(5,5) : 1

Time Complexity: O(sqrt(N))

Auxiliary Space: O(MAXN), since MAXN extra space has been taken, where MAXN is the maximum value of N


Article Tags :