Article Categories
- All Categories
-
Data Structure
-
Networking
-
RDBMS
-
Operating System
-
Java
-
MS Excel
-
iOS
-
HTML
-
CSS
-
Android
-
Python
-
C Programming
-
C++
-
C#
-
MongoDB
-
MySQL
-
Javascript
-
PHP
-
Economics & Finance
JavaScript Program for Range LCM Queries
LCM stands for the Least Common Multiple, and the LCM of a set of numbers is the smallest positive integer that is divisible by all the numbers in the given set. In this article, we will implement a JavaScript program to handle range LCM queries efficiently.
Problem Statement
We are given an array of integers and another array of queries. Each query contains a pair of indices representing a range in the original array. For each query, we need to calculate the LCM of all elements within that range.
For example, if the array is [1, 2, 3, 4, 5, 6] and queries are [[1,3], [2,5]]:
- First query: elements
[2, 3, 4]? LCM = 12 - Second query: elements
[3, 4, 5, 6]? LCM = 60
Mathematical Relationship Between LCM and GCD
To solve this efficiently, we use the mathematical relationship between LCM and GCD (Greatest Common Divisor):
For two numbers a and b: LCM(a, b) = (a × b) / GCD(a, b) For multiple numbers: LCM can be computed iteratively using this formula
We can find GCD using the Euclidean algorithm with logarithmic time complexity.
Naive Approach
The straightforward approach is to process each query by iterating through the range and computing LCM step by step:
// Function to find GCD using Euclidean algorithm
function gcd(a, b) {
if (a == 0) {
return b;
}
return gcd(b % a, a);
}
// Function to find LCM of two numbers
function lcm(a, b) {
return (a * b) / gcd(a, b);
}
// Function to find LCM in a given range
function lcmRange(arr, l, r) {
let result = arr[l];
for (let i = l + 1; i <= r; i++) {
result = lcm(result, arr[i]);
}
console.log(`LCM of range [${l}, ${r}] is: ${result}`);
return result;
}
// Example usage
const arr = [1, 2, 3, 4, 5, 6];
const queries = [[1, 3], [2, 5]];
// Process all queries
queries.forEach((query, index) => {
console.log(`Query ${index + 1}:`);
lcmRange(arr, query[0], query[1]);
});
Query 1: LCM of range [1, 3] is: 12 Query 2: LCM of range [2, 5] is: 60
Optimized Segment Tree Approach
For multiple queries, we can use a Segment Tree to preprocess the array and answer queries in logarithmic time:
class SegmentTree {
constructor(arr) {
this.n = arr.length;
this.tree = new Array(4 * this.n);
this.arr = arr;
this.build(0, this.n - 1, 1);
}
gcd(a, b) {
return b === 0 ? a : this.gcd(b, a % b);
}
lcm(a, b) {
return (a * b) / this.gcd(a, b);
}
build(start, end, node) {
if (start === end) {
this.tree[node] = this.arr[start];
return;
}
const mid = Math.floor((start + end) / 2);
this.build(start, mid, 2 * node);
this.build(mid + 1, end, 2 * node + 1);
this.tree[node] = this.lcm(this.tree[2 * node], this.tree[2 * node + 1]);
}
query(start, end, l, r, node) {
// No overlap
if (end < l || start > r) {
return 1; // LCM identity
}
// Complete overlap
if (l <= start && r >= end) {
return this.tree[node];
}
// Partial overlap
const mid = Math.floor((start + end) / 2);
const leftLcm = this.query(start, mid, l, r, 2 * node);
const rightLcm = this.query(mid + 1, end, l, r, 2 * node + 1);
return this.lcm(leftLcm, rightLcm);
}
rangeLCM(l, r) {
return this.query(0, this.n - 1, l, r, 1);
}
}
// Example usage
const arr = [1, 2, 3, 4, 5, 6];
const segTree = new SegmentTree(arr);
const queries = [[1, 3], [2, 5]];
queries.forEach((query, index) => {
const result = segTree.rangeLCM(query[0], query[1]);
console.log(`Query ${index + 1}: LCM of range [${query[0]}, ${query[1]}] = ${result}`);
});
Query 1: LCM of range [1, 3] = 12 Query 2: LCM of range [2, 5] = 60
Complexity Analysis
| Approach | Time Complexity | Space Complexity | Best For |
|---|---|---|---|
| Naive | O(Q × N × log(D)) | O(1) | Few queries |
| Segment Tree | O(N + Q × log(N)) | O(N) | Many queries |
Where Q = number of queries, N = array size, D = maximum element value
Conclusion
We explored two approaches for range LCM queries: a naive O(Q×N×log(D)) solution and an optimized segment tree approach with O(Q×log(N)) query time. The segment tree approach is preferred when dealing with multiple queries on the same array.
