Given an array arr containing N positive integers and the number of queries Q, for each query task is to find the maximum pair sum in the given index range [L, R] where L and R are the respective low and high indices.
Examples:
Input: arr = {3, 4, 5, 6, 7, 8}, Q[][2] = [[0, 3], [3, 5]]
Output:
11
15
Explanation:
For the first query, subarray is [3, 4, 5, 6]
All the pairs are (3, 4), (3, 5), (3, 6), (4, 5), (4, 6), (5, 6)
Hence the maximum pair sum = (5 + 6) = 11
For the second query, subarray is [6, 7, 8]
All the pairs of the subarray are (6, 7), (6, 8), (7, 8)
Hence the maximum pair sum = (7 + 8) = 15
Naive Approach: For each query range, do the following
- Find the maximum and the second maximum in the given query range.
- Sum of maximum and second maximum will be the maximum pair sum of the given range.
Below is the implementation of the above approach:
C++
// C++ program to find maximum // pair sum in the given // index range of an Array #include <bits/stdc++.h> using namespace std; // Node structure to store a query struct node { int f; int s; }; // Function to find the required sum void findSum( int * arr, int n, int Q, node* query) { // Run a loop to iterate // over query array for ( int i = 0; i < Q; i++) { // declare first 'f' // and second 's' variables int f, s; // Initialise them with 0 f = s = 0; // Iterate over the // given array from // range query[i].f to query[i].s for ( int j = query[i].f; j <= query[i].s; j++) { // If the array element // value is greater than // current f, store // current f in s and // array element value in f if (arr[j] >= f) { s = f; f = arr[j]; } // else if element // is greater than s, // update s with // array element value else if (arr[j] > s) s = arr[j]; } // print the sum of f and s cout << (f + s) << endl; } } // Driver code int main() { // Given array and number of queries int arr[] = { 3, 4, 5, 6, 7, 8 }, Q = 2; int n = sizeof (arr) / sizeof (arr[0]); // Declare and define queries node query[Q]; query[0] = { 0, 3 }; query[1] = { 3, 5 }; findSum(arr, n, Q, query); } |
Java
// Java program to find maximum // pair sum in the given // index range of an Array class GFG{ // Node structure to store a query static class node { int f; int s; public node( int f, int s) { this .f = f; this .s = s; } }; // Function to find the required sum static void findSum( int []arr, int n, int Q, node []query) { // Run a loop to iterate // over query array for ( int i = 0 ; i < Q; i++) { // declare first 'f' // and second 's' variables int f, s; // Initialise them with 0 f = s = 0 ; // Iterate over the // given array from // range query[i].f to query[i].s for ( int j = query[i].f; j <= query[i].s; j++) { // If the array element // value is greater than // current f, store // current f in s and // array element value in f if (arr[j] >= f) { s = f; f = arr[j]; } // else if element // is greater than s, // update s with // array element value else if (arr[j] > s) s = arr[j]; } // print the sum of f and s System.out.print((f + s) + "\n" ); } } // Driver code public static void main(String[] args) { // Given array and number of queries int arr[] = { 3 , 4 , 5 , 6 , 7 , 8 }, Q = 2 ; int n = arr.length; // Declare and define queries node []query = new node[ 2 ]; query[ 0 ] = new node( 0 , 3 ); query[ 1 ] = new node( 3 , 5 ); findSum(arr, n, Q, query); } } // This code is contributed by PrinciRaj1992 |
C#
// C# program to find maximum // pair sum in the given // index range of an Array using System; class GFG{ // Node structure to store a query class node { public int f; public int s; public node( int f, int s) { this .f = f; this .s = s; } }; // Function to find the required sum static void findSum( int []arr, int n, int Q, node []query) { // Run a loop to iterate // over query array for ( int i = 0; i < Q; i++) { // declare first 'f' // and second 's' variables int f, s; // Initialise them with 0 f = s = 0; // Iterate over the // given array from // range query[i].f to query[i].s for ( int j = query[i].f; j <= query[i].s; j++) { // If the array element // value is greater than // current f, store // current f in s and // array element value in f if (arr[j] >= f) { s = f; f = arr[j]; } // else if element // is greater than s, // update s with // array element value else if (arr[j] > s) s = arr[j]; } // print the sum of f and s Console.Write((f + s) + "\n" ); } } // Driver code public static void Main(String[] args) { // Given array and number of queries int []arr = { 3, 4, 5, 6, 7, 8 }; int Q = 2; int n = arr.Length; // Declare and define queries node []query = new node[2]; query[0] = new node( 0, 3 ); query[1] = new node(3, 5 ); findSum(arr, n, Q, query); } } // This code is contributed by PrinciRaj1992 |
11 15
Performance Analysis:
- Time Complexity: In the above approach, we are looper over the array of length N for each of Q query. Thus the time complexity would be O(N*Q).
- Auxiliary Space: In the above approach there is no extra space used, therefore the Auxiliary Space complexity will be O(1).
Efficient Approach: The idea is to use the segment tree where each node of the segment tree store two values:
- Maximum of the given below subtree
- Second maximum of the given below subtree
- If size of the array is 1, then we simply store first max=arr[start] and second max=0 where start is the index of the array.
- Else
- Recursively determine the firstMax
(l1)
and the second max(l2)
for the left half of the array. - Recursively determine the firstMax
(r1)
and the second max(r2)
for the right half of the array.
- Recursively determine the firstMax
- Now we will determine the first max and the second max of the present node as
firstMax=max(l1, r1)
andsecondMax=max(min(l1, r1), max(l2, r2))
- If the range of the node is within l and r then return the value of the present
node - else if the range of the node is completely outside l and r then return 0
- else recursively find
first max(l1)
andsecond max(l2)
from
left half and thefirstMax(r1)
and thesecondMax(r2)
from the right
half. - return the
max(l1, r1) and max(min(l1, r1), max(l2, r2)).
- Time Complexity: In the above approach, we are building a segment tree which is of time complexity O(N) Then for each of Q queries, we find the solution in O(logN) time. So overall time complexity is O(N+Q*logN)
- Auxiliary Space Complexity: In the above approach, we are using extra space for storing the segment tree which is taking (4 * N + 1) space. So Auxiliary space complexity is O(N)
Algorithm to build the required segment tree
Algorithm for the Query to find maximum pair sum of given range
Below is the implementation of the above approach:
CPP
// C++ program to find maximum // pair sum in the given // index range of an Array #include <bits/stdc++.h> using namespace std; // Node structure to store a query struct node { int f; int s; }; // Function to build the tree void build( int arr[], node tree[], int start, int end, int index) { // If there is just one element // in the array range, // set maximum as that element, // and second maximum as zero if (start == end) { tree[index].f = arr[start]; tree[index].s = 0; return ; } // Calculate the mid value int mid = start + (end - start) / 2; // Recursively build the tree // for the range [start, mid] // and store the value // at index (2 * index + 1) build( arr, tree, start, mid, 2 * index + 1); // Recursively build the tree // for the range [mid + 1, end] // and store the value // at index (2 * index + 2) build( arr, tree, mid + 1, end, 2 * index + 2); // Get the maximum and // second maximum from // both left and right subtrees int l1 = tree[2 * index + 1].f; int l2 = tree[2 * index + 1].s; int r1 = tree[2 * index + 2].f; int r2 = tree[2 * index + 2].s; // Set the maximum for this node as // maximum of l1 and r1 tree[index].f = max(l1, r1); // Set the second maximum for this // node as maximum of // min(l1, r1) & max(l2, r2) tree[index].s = max(min(l1, r1), max(l2, r2)); } // Function to execute a // query on the segment tree node runQuery( node tree[], int start, int end, int index, int L, int R) { // If the range of // the node is completely // outside l and r then return 0 if (R < start or L > end) { return { 0, 0 }; } // If the range of the // node is within l and r // then return the value // of the present node if (L <= start and R >= end) { return tree[index]; } // calculate mid value int mid = start + (end - start) / 2; // Recursively find first // max and second max from // the left half node Left = runQuery( tree, start, mid, 2 * index + 1, L, R); // Recursively find first // max and second max from // the right half node Right = runQuery( tree, mid + 1, end, 2 * index + 2, L, R); // Get the values // of l1, l2, r1, r2 int l1 = Left.f; int l2 = Left.s; int r1 = Right.f; int r2 = Right.s; // return the maximum // as max(l1, r1), and // second maximum as // max(min(l1, r1), max(l2, r2)) return { max(l1, r1), max(min(l1, r1), max(l2, r2)) }; } // Function to find the required sum void findSum( int * arr, int n, int Q, node* query) { // Declare an array of // length '4 * n + 1' and // build the tree node tree[4 * n + 1]; build(arr, tree, 0, n - 1, 0); // Run a loop to iterate // over each query for ( int i = 0; i < Q; i++) { // Call the query function // with given range node temp = runQuery( tree, 0, n - 1, 0, query[i].f, query[i].s); // Store maximum and second // maximum in variables int f = temp.f; int s = temp.s; // Return sum of the maximum // and second maximum cout << (f + s) << endl; } } // Driver code int main() { // Given array and number of queries int arr[] = { 3, 4, 5, 6, 7, 8 }, Q = 2; int n = sizeof (arr) / sizeof (arr[0]); // Declare and define queries node query[Q]; query[0] = { 0, 3 }; query[1] = { 3, 5 }; findSum(arr, n, Q, query); } |
Java
// Java program to find maximum // pair sum in the given // index range of an Array class GFG{ // Node structure to store a query static class node { int f; int s; public node( int f, int s) { this .f = f; this .s = s; } public node() { // TODO Auto-generated constructor stub } }; // Function to build the tree static void build( int arr[], node tree[], int start, int end, int index) { // If there is just one element // in the array range, // set maximum as that element, // and second maximum as zero if (start == end ) { tree[index].f = arr[start]; tree[index].s = 0 ; return ; } // Calculate the mid value int mid = start + (end - start) / 2 ; // Recursively build the tree // for the range [start, mid] // and store the value // at index (2 * index + 1) build( arr, tree, start, mid, 2 * index + 1 ); // Recursively build the tree // for the range [mid + 1, end] // and store the value // at index (2 * index + 2) build( arr, tree, mid + 1 , end, 2 * index + 2 ); // Get the maximum and // second maximum from // both left and right subtrees int l1 = tree[ 2 * index + 1 ].f; int l2 = tree[ 2 * index + 1 ].s; int r1 = tree[ 2 * index + 2 ].f; int r2 = tree[ 2 * index + 2 ].s; // Set the maximum for this node as // maximum of l1 and r1 tree[index].f = Math.max(l1, r1); // Set the second maximum for this // node as maximum of // Math.min(l1, r1) & Math.max(l2, r2) tree[index].s = Math.max(Math.min(l1, r1), Math.max(l2, r2)); } // Function to execute a // query on the segment tree static node runQuery( node tree[], int start, int end, int index, int L, int R) { // If the range of // the node is completely // outside l and r then return 0 if (R < start || L > end) { return new node( 0 , 0 ); } // If the range of the // node is within l and r // then return the value // of the present node if (L <= start && R >= end) { return tree[index]; } // calculate mid value int mid = start + (end - start) / 2 ; // Recursively find first // max and second max from // the left half node Left = runQuery( tree, start, mid, 2 * index + 1 , L, R); // Recursively find first // max and second max from // the right half node Right = runQuery( tree, mid + 1 , end, 2 * index + 2 , L, R); // Get the values // of l1, l2, r1, r2 int l1 = Left.f; int l2 = Left.s; int r1 = Right.f; int r2 = Right.s; // return the maximum // as Math.max(l1, r1), and // second maximum as // Math.max(Math.min(l1, r1), Math.max(l2, r2)) return new node( Math.max(l1, r1), Math.max(Math.min(l1, r1), Math.max(l2, r2)) ); } // Function to find the required sum static void findSum( int []arr, int n, int Q, node []query) { // Declare an array of // length '4 * n + 1' and // build the tree node []tree = new node[ 4 * n + 1 ]; for ( int i= 0 ;i< 4 * n + 1 ;i++) { tree[i] = new node(); } build(arr, tree, 0 , n - 1 , 0 ); // Run a loop to iterate // over each query for ( int i = 0 ; i < Q; i++) { // Call the query function // with given range node temp = runQuery( tree, 0 , n - 1 , 0 , query[i].f, query[i].s); // Store maximum and second // maximum in variables int f = temp.f; int s = temp.s; // Return sum of the maximum // and second maximum System.out.print((f + s) + "\n" ); } } // Driver code public static void main(String[] args) { // Given array and number of queries int arr[] = { 3 , 4 , 5 , 6 , 7 , 8 }, Q = 2 ; int n = arr.length; // Declare and define queries node []query = new node[Q]; query[ 0 ] = new node( 0 , 3 ); query[ 1 ] = new node( 3 , 5 ); findSum(arr, n, Q, query); } } // This code is contributed by Princi Singh |
C#
// C# program to find maximum // pair sum in the given // index range of an Array using System; class GFG{ // Node structure to store a query class node { public int f; public int s; public node( int f, int s) { this .f = f; this .s = s; } public node() { // TODO Auto-generated constructor stub } }; // Function to build the tree static void build( int []arr, node []tree, int start, int end, int index) { // If there is just one element // in the array range, // set maximum as that element, // and second maximum as zero if (start == end ) { tree[index].f = arr[start]; tree[index].s = 0; return ; } // Calculate the mid value int mid = start + (end - start) / 2; // Recursively build the tree // for the range [start, mid] // and store the value // at index (2 * index + 1) build( arr, tree, start, mid, 2 * index + 1); // Recursively build the tree // for the range [mid + 1, end] // and store the value // at index (2 * index + 2) build( arr, tree, mid + 1, end, 2 * index + 2); // Get the maximum and // second maximum from // both left and right subtrees int l1 = tree[2 * index + 1].f; int l2 = tree[2 * index + 1].s; int r1 = tree[2 * index + 2].f; int r2 = tree[2 * index + 2].s; // Set the maximum for this node as // maximum of l1 and r1 tree[index].f = Math.Max(l1, r1); // Set the second maximum for this // node as maximum of // Math.Min(l1, r1) & Math.Max(l2, r2) tree[index].s = Math.Max(Math.Min(l1, r1), Math.Max(l2, r2)); } // Function to execute a // query on the segment tree static node runQuery( node []tree, int start, int end, int index, int L, int R) { // If the range of // the node is completely // outside l and r then return 0 if (R < start || L > end) { return new node( 0, 0 ); } // If the range of the // node is within l and r // then return the value // of the present node if (L <= start && R >= end) { return tree[index]; } // calculate mid value int mid = start + (end - start) / 2; // Recursively find first // max and second max from // the left half node Left = runQuery( tree, start, mid, 2 * index + 1, L, R); // Recursively find first // max and second max from // the right half node Right = runQuery( tree, mid + 1, end, 2 * index + 2, L, R); // Get the values // of l1, l2, r1, r2 int l1 = Left.f; int l2 = Left.s; int r1 = Right.f; int r2 = Right.s; // return the maximum // as Math.Max(l1, r1), and // second maximum as // Math.Max(Math.Min(l1, r1), Math.Max(l2, r2)) return new node( Math.Max(l1, r1), Math.Max(Math.Min(l1, r1), Math.Max(l2, r2)) ); } // Function to find the required sum static void findSum( int []arr, int n, int Q, node []query) { // Declare an array of // length '4 * n + 1' and // build the tree node []tree = new node[4 * n + 1]; for ( int i=0;i<4 * n + 1;i++) { tree[i] = new node(); } build(arr, tree, 0, n - 1, 0); // Run a loop to iterate // over each query for ( int i = 0; i < Q; i++) { // Call the query function // with given range node temp = runQuery( tree, 0, n - 1, 0, query[i].f, query[i].s); // Store maximum and second // maximum in variables int f = temp.f; int s = temp.s; // Return sum of the maximum // and second maximum Console.Write((f + s) + "\n" ); } } // Driver code public static void Main(String[] args) { // Given array and number of queries int []arr = { 3, 4, 5, 6, 7, 8 }; int Q = 2; int n = arr.Length; // Declare and define queries node []query = new node[Q]; query[0] = new node( 0, 3 ); query[1] = new node( 3, 5 ); findSum(arr, n, Q, query); } } // This code is contributed by Rajput-Ji |
11 15
Performance Analysis:
Attention reader! Don’t stop learning now. Get hold of all the important DSA concepts with the DSA Self Paced Course at a student-friendly price and become industry ready.