Given an array arr[] of integers of size N and an array of Q queries, query[], where each query is of type [L, R] denoting the range from index L to index R, the task is to find the LCM of all the numbers of the range for all the queries.
Examples:
Input: arr[] = {5, 7, 5, 2, 10, 12 ,11, 17, 14, 1, 44}
query[] = {{2, 5}, {5, 10}, {0, 10}}
Output: 60,15708, 78540
Explanation: In the first query LCM(5, 2, 10, 12) = 60
In the second query LCM(12, 11, 17, 14, 1, 44) = 15708
In the last query LCM(5, 7, 5, 2, 10, 12, 11, 17, 14, 1, 44) = 78540
Input: arr[] = {2, 4, 8, 16}, query[] = {{2, 3}, {0, 1}}
Output: 16, 4
Naive Approach: The approach is based on the following mathematical idea:
Mathematically, LCM(l, r) = LCM(arr[l], arr[l+1] , . . . ,arr[r-1], arr[r]) and
LCM(a, b) = (a*b) / GCD(a,b)
So traverse the array for every query and calculate the answer by using the above formula for LCM.
Time Complexity: O(N * Q)
Auxiliary Space: O(1)
As the number of queries can be large, the naive solution would be impractical. This time can be reduced
There is no update operation in this problem. So we can initially build a segment tree and use that to answer the queries in logarithmic time.
Each node in the tree should store the LCM value for that particular segment and we can use the same formula as above to combine the segments.
Follow the steps mentioned below to implement the idea:
- Build a segment tree from the given array.
- Traverse through the queries. For each query:
- Find that particular range in the segment tree.
- Use the above mentioned formula to combine the segments and calculate the LCM for that range.
- Print the answer for that segment.
Below is the implementation of the above approach.
C++
#include <bits/stdc++.h>
using namespace std;
#define MAX 1000
int tree[4 * MAX];
int arr[MAX];
int gcd( int a, int b)
{
if (a == 0)
return b;
return gcd(b % a, a);
}
int lcm( int a, int b) { return a * b / gcd(a, b); }
void build( int node, int start, int end)
{
if (start == end) {
tree[node] = arr[start];
return ;
}
int mid = (start + end) / 2;
build(2 * node, start, mid);
build(2 * node + 1, mid + 1, end);
int left_lcm = tree[2 * node];
int right_lcm = tree[2 * node + 1];
tree[node] = lcm(left_lcm, right_lcm);
}
int query( int node, int start, int end, int l, int r)
{
if (end < l || start > r)
return 1;
if (l <= start && r >= end)
return tree[node];
int mid = (start + end) / 2;
int left_lcm = query(2 * node, start, mid, l, r);
int right_lcm = query(2 * node + 1, mid + 1, end, l, r);
return lcm(left_lcm, right_lcm);
}
int main()
{
arr[0] = 5;
arr[1] = 7;
arr[2] = 5;
arr[3] = 2;
arr[4] = 10;
arr[5] = 12;
arr[6] = 11;
arr[7] = 17;
arr[8] = 14;
arr[9] = 1;
arr[10] = 44;
build(1, 0, 10);
cout << query(1, 0, 10, 2, 5) << endl;
cout << query(1, 0, 10, 5, 10) << endl;
cout << query(1, 0, 10, 0, 10) << endl;
return 0;
}
|
Java
class GFG {
static final int MAX = 1000 ;
static int tree[] = new int [ 4 * MAX];
static int arr[] = new int [MAX];
static int gcd( int a, int b)
{
if (a == 0 ) {
return b;
}
return gcd(b % a, a);
}
static int lcm( int a, int b)
{
return a * b / gcd(a, b);
}
static void build( int node, int start, int end)
{
if (start == end) {
tree[node] = arr[start];
return ;
}
int mid = (start + end) / 2 ;
build( 2 * node, start, mid);
build( 2 * node + 1 , mid + 1 , end);
int left_lcm = tree[ 2 * node];
int right_lcm = tree[ 2 * node + 1 ];
tree[node] = lcm(left_lcm, right_lcm);
}
static int query( int node, int start, int end, int l,
int r)
{
if (end < l || start > r) {
return 1 ;
}
if (l <= start && r >= end) {
return tree[node];
}
int mid = (start + end) / 2 ;
int left_lcm = query( 2 * node, start, mid, l, r);
int right_lcm
= query( 2 * node + 1 , mid + 1 , end, l, r);
return lcm(left_lcm, right_lcm);
}
public static void main(String[] args)
{
arr[ 0 ] = 5 ;
arr[ 1 ] = 7 ;
arr[ 2 ] = 5 ;
arr[ 3 ] = 2 ;
arr[ 4 ] = 10 ;
arr[ 5 ] = 12 ;
arr[ 6 ] = 11 ;
arr[ 7 ] = 17 ;
arr[ 8 ] = 14 ;
arr[ 9 ] = 1 ;
arr[ 10 ] = 44 ;
build( 1 , 0 , 10 );
System.out.println(query( 1 , 0 , 10 , 2 , 5 ));
System.out.println(query( 1 , 0 , 10 , 5 , 10 ));
System.out.println(query( 1 , 0 , 10 , 0 , 10 ));
}
}
|
Python3
MAX = 1000
tree = [ 0 ] * ( 4 * MAX )
arr = [ 0 ] * MAX
def gcd(a: int , b: int ):
if a = = 0 :
return b
return gcd(b % a, a)
def lcm(a: int , b: int ):
return (a * b) / / gcd(a, b)
def build(node: int , start: int , end: int ):
if start = = end:
tree[node] = arr[start]
return
mid = (start + end) / / 2
build( 2 * node, start, mid)
build( 2 * node + 1 , mid + 1 , end)
left_lcm = tree[ 2 * node]
right_lcm = tree[ 2 * node + 1 ]
tree[node] = lcm(left_lcm, right_lcm)
def query(node: int , start: int ,
end: int , l: int , r: int ):
if end < l or start > r:
return 1
if l < = start and r > = end:
return tree[node]
mid = (start + end) / / 2
left_lcm = query( 2 * node, start, mid, l, r)
right_lcm = query( 2 * node + 1 ,
mid + 1 , end, l, r)
return lcm(left_lcm, right_lcm)
if __name__ = = "__main__" :
arr[ 0 ] = 5
arr[ 1 ] = 7
arr[ 2 ] = 5
arr[ 3 ] = 2
arr[ 4 ] = 10
arr[ 5 ] = 12
arr[ 6 ] = 11
arr[ 7 ] = 17
arr[ 8 ] = 14
arr[ 9 ] = 1
arr[ 10 ] = 44
build( 1 , 0 , 10 )
print (query( 1 , 0 , 10 , 2 , 5 ))
print (query( 1 , 0 , 10 , 5 , 10 ))
print (query( 1 , 0 , 10 , 0 , 10 ))
|
C#
using System;
using System.Collections.Generic;
class GFG {
static readonly int MAX = 1000;
static int [] tree = new int [4 * MAX];
static int [] arr = new int [MAX];
static int gcd( int a, int b)
{
if (a == 0) {
return b;
}
return gcd(b % a, a);
}
static int lcm( int a, int b)
{
return a * b / gcd(a, b);
}
static void build( int node, int start, int end)
{
if (start == end) {
tree[node] = arr[start];
return ;
}
int mid = (start + end) / 2;
build(2 * node, start, mid);
build(2 * node + 1, mid + 1, end);
int left_lcm = tree[2 * node];
int right_lcm = tree[2 * node + 1];
tree[node] = lcm(left_lcm, right_lcm);
}
static int query( int node, int start, int end, int l,
int r)
{
if (end < l || start > r) {
return 1;
}
if (l <= start && r >= end) {
return tree[node];
}
int mid = (start + end) / 2;
int left_lcm = query(2 * node, start, mid, l, r);
int right_lcm
= query(2 * node + 1, mid + 1, end, l, r);
return lcm(left_lcm, right_lcm);
}
public static void Main(String[] args)
{
arr[0] = 5;
arr[1] = 7;
arr[2] = 5;
arr[3] = 2;
arr[4] = 10;
arr[5] = 12;
arr[6] = 11;
arr[7] = 17;
arr[8] = 14;
arr[9] = 1;
arr[10] = 44;
build(1, 0, 10);
Console.WriteLine(query(1, 0, 10, 2, 5));
Console.WriteLine(query(1, 0, 10, 5, 10));
Console.WriteLine(query(1, 0, 10, 0, 10));
}
}
|
Javascript
<script>
const MAX = 1000
var tree = new Array(4*MAX);
var arr = new Array(MAX);
function gcd(a, b)
{
if (a == 0)
return b;
return gcd(b%a, a);
}
function lcm(a, b)
{
return Math.floor(a*b/gcd(a,b));
}
function build(node, start, end)
{
if (start==end)
{
tree[node] = arr[start];
return ;
}
let mid = Math.floor((start+end)/2);
build(2*node, start, mid);
build(2*node+1, mid+1, end);
let left_lcm = tree[2*node];
let right_lcm = tree[2*node+1];
tree[node] = lcm(left_lcm, right_lcm);
}
function query(node, start, end, l, r)
{
if (end<l || start>r)
return 1;
if (l<=start && r>=end)
return tree[node];
let mid = Math.floor((start+end)/2);
let left_lcm = query(2*node, start, mid, l, r);
let right_lcm = query(2*node+1, mid+1, end, l, r);
return lcm(left_lcm, right_lcm);
}
arr[0] = 5;
arr[1] = 7;
arr[2] = 5;
arr[3] = 2;
arr[4] = 10;
arr[5] = 12;
arr[6] = 11;
arr[7] = 17;
arr[8] = 14;
arr[9] = 1;
arr[10] = 44;
build(1, 0, 10);
document.write(query(1, 0, 10, 2, 5) + "<br>" );
document.write(query(1, 0, 10, 5, 10) + "<br>" );
document.write(query(1, 0, 10, 0, 10) + "<br>" );
</script>
|
Time Complexity: O(Log N * Log n) where N is the number of elements in the array. The other log n denotes the time required for finding the LCM. This time complexity is for each query. The total time complexity is O(N + Q*Log N*log n), this is because O(N) time is required to build the tree and then to answer the queries.
Auxiliary Space: O(N), where N is the number of elements in the array. This space is required for storing the segment tree.
Related Topic: Segment Tree
If you like GeeksforGeeks and would like to contribute, you can also write an article using write.geeksforgeeks.org or mail your article to review-team@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.
Approach#2: Using math
We first define a helper function lcm() to calculate the least common multiple of two numbers. Then, for each query, we iterate through the subarray of arr defined by the query range and calculate the LCM using the lcm() function. The LCM value is stored in a list, which is returned as the final result.
Algorithm
1. Define a helper function lcm(a, b) to calculate the least common multiple of two numbers.
2. Define a function range_lcm_queries(arr, queries) that takes an array arr and a list of query ranges queries as input.
3. Create an empty list results to store the LCM values for each query.
4. For each query in queries, extract the left and right indices l and r.
5. Set lcm_val to the value of arr[l].
6. For each index i in the range l+1 to r, update lcm_val to be the LCM of lcm_val and arr[i] using the lcm() function.
7. Append lcm_val to the results list.
8. Return the results list.
C++
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int gcd( int a, int b) {
if (b == 0)
return a;
return gcd(b, a % b);
}
int lcm( int a, int b) {
return a * b / gcd(a, b);
}
vector< int > rangeLcmQueries(vector< int >& arr, vector<pair< int , int >>& queries) {
vector< int > results;
for ( const auto & query : queries) {
int l = query.first;
int r = query.second;
int lcmVal = arr[l];
for ( int i = l + 1; i <= r; i++) {
lcmVal = lcm(lcmVal, arr[i]);
}
results.push_back(lcmVal);
}
return results;
}
int main() {
vector< int > arr = {5, 7, 5, 2, 10, 12, 11, 17, 14, 1, 44};
vector<pair< int , int >> queries = {{2, 5}, {5, 10}, {0, 10}};
vector< int > results = rangeLcmQueries(arr, queries);
for ( const auto & result : results) {
cout << result << " " ;
}
cout << endl;
return 0;
}
|
Java
import java.util.ArrayList;
import java.util.List;
public class GFG {
public static int gcd( int a, int b) {
if (b == 0 )
return a;
return gcd(b, a % b);
}
public static int lcm( int a, int b) {
return a * b / gcd(a, b);
}
public static List<Integer> rangeLcmQueries(List<Integer> arr, List< int []> queries) {
List<Integer> results = new ArrayList<>();
for ( int [] query : queries) {
int l = query[ 0 ];
int r = query[ 1 ];
int lcmVal = arr.get(l);
for ( int i = l + 1 ; i <= r; i++) {
lcmVal = lcm(lcmVal, arr.get(i));
}
results.add(lcmVal);
}
return results;
}
public static void main(String[] args) {
List<Integer> arr = List.of( 5 , 7 , 5 , 2 , 10 , 12 , 11 , 17 , 14 , 1 , 44 );
List< int []> queries = List.of( new int []{ 2 , 5 }, new int []{ 5 , 10 }, new int []{ 0 , 10 });
List<Integer> results = rangeLcmQueries(arr, queries);
for ( int result : results) {
System.out.print(result + " " );
}
System.out.println();
}
}
|
Python3
from math import gcd
def lcm(a, b):
return a * b / / gcd(a, b)
def range_lcm_queries(arr, queries):
results = []
for query in queries:
l, r = query
lcm_val = arr[l]
for i in range (l + 1 , r + 1 ):
lcm_val = lcm(lcm_val, arr[i])
results.append(lcm_val)
return results
arr = [ 5 , 7 , 5 , 2 , 10 , 12 , 11 , 17 , 14 , 1 , 44 ]
queries = [( 2 , 5 ), ( 5 , 10 ), ( 0 , 10 )]
print (range_lcm_queries(arr, queries))
|
C#
using System;
using System.Collections.Generic;
class GFG
{
static int GCD( int a, int b)
{
if (b == 0)
return a;
return GCD(b, a % b);
}
static int LCM( int a, int b)
{
return a * b / GCD(a, b);
}
static List< int > RangeLcmQueries(List< int > arr, List<Tuple< int , int >> queries)
{
List< int > results = new List< int >();
foreach ( var query in queries)
{
int l = query.Item1;
int r = query.Item2;
int lcmVal = arr[l];
for ( int i = l + 1; i <= r; i++)
{
lcmVal = LCM(lcmVal, arr[i]);
}
results.Add(lcmVal);
}
return results;
}
static void Main()
{
List< int > arr = new List< int > { 5, 7, 5, 2, 10, 12, 11, 17, 14, 1, 44 };
List<Tuple< int , int >> queries = new List<Tuple< int , int >> {
Tuple.Create(2, 5),
Tuple.Create(5, 10),
Tuple.Create(0, 10)
};
List< int > results = RangeLcmQueries(arr, queries);
foreach ( var result in results)
{
Console.Write(result + " " );
}
Console.WriteLine();
}
}
|
Javascript
function gcd(a, b) {
if (b === 0) {
return a;
}
return gcd(b, a % b);
}
function lcm(a, b) {
return (a * b) / gcd(a, b);
}
function rangeLcmQueries(arr, queries) {
const results = [];
for (const query of queries) {
const l = query[0];
const r = query[1];
let lcmVal = arr[l];
for (let i = l + 1; i <= r; i++) {
lcmVal = lcm(lcmVal, arr[i]);
}
results.push(lcmVal);
}
return results;
}
const arr = [5, 7, 5, 2, 10, 12, 11, 17, 14, 1, 44];
const queries = [[2, 5], [5, 10], [0, 10]];
const results = rangeLcmQueries(arr, queries);
for (const result of results) {
console.log(result + " " );
}
console.log();
|
Output
[60, 15708, 78540]
Time Complexity: O(log(min(a,b))). For each query range, we iterate through a subarray of size O(n), where n is the length of arr. Therefore, the time complexity of the overall function is O(qn log(min(a_i))) where q is the number of queries and a_i is the i-th element of arr.
Space Complexity: O(1) since we are only storing a few integers at a time. The space used by the input arr and queries is not considered.
Feeling lost in the world of random DSA topics, wasting time without progress? It's time for a change! Join our DSA course, where we'll guide you on an exciting journey to master DSA efficiently and on schedule.
Ready to dive in? Explore our Free Demo Content and join our DSA course, trusted by over 100,000 geeks!
Last Updated :
24 Aug, 2023
Like Article
Save Article