Maximum pair sum in the given index ranges of an Array

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

  1. Find the maximum and the second maximum in the given query range.
  2. 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++



filter_none

edit
close

play_arrow

link
brightness_4
code

// 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);
}

chevron_right


Java

filter_none

edit
close

play_arrow

link
brightness_4
code

// 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

chevron_right


C#

filter_none

edit
close

play_arrow

link
brightness_4
code

// 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

chevron_right


Output:

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
    • Algorithm to build the required segment tree

      1. 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.
      2. 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.
      3. Now we will determine the first max and the second max of the present node as
        firstMax=max(l1, r1) and secondMax=max(min(l1, r1), max(l2, r2))

        Algorithm for the Query to find maximum pair sum of given range

        1. If the range of the node is within l and r then return the value of the present
          node
        2. else if the range of the node is completely outside l and r then return 0
        3. else recursively find first max(l1) and second max(l2) from
          left half and the firstMax(r1) and the secondMax(r2) from the right
          half.

        4. return the max(l1, r1) and max(min(l1, r1), max(l2, r2)).

        Below is the implementation of the above approach:

        CPP

        filter_none

        edit
        close

        play_arrow

        link
        brightness_4
        code

        // 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);
        }

        chevron_right

        
        

        Java

        filter_none

        edit
        close

        play_arrow

        link
        brightness_4
        code

        // 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

        chevron_right

        
        

        C#

        filter_none

        edit
        close

        play_arrow

        link
        brightness_4
        code

        // 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

        chevron_right

        
        

        Output:

        11
        15
        

        Performance Analysis:

        • 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)

        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.




        My Personal Notes arrow_drop_up

        Check out this Author's contributed articles.

        If you like GeeksforGeeks and would like to contribute, you can also write an article using contribute.geeksforgeeks.org or mail your article to contribute@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.

        Please Improve this article if you find anything incorrect by clicking on the "Improve Article" button below.