Open In App

Maximum prefix-sum for a given range

Improve
Improve
Like Article
Like
Save
Share
Report

Given an array of n integers and q queries, each query having a range from l to r. Find the maximum prefix-sum for the range l – r.

Examples: 

Input: a[] = {-1, 2, 3, -5} 
       q = 2
       l = 0, r = 3
       l = 1, r = 3

Output: 4
        5

Explanation:- The range (0, 3) in the 1st query has
              [-1, 2, 3, -5], since it is prefix, 
              we have to start from -1. Hence, the 
              max prefix sum will be -1 + 2 + 3 = 4.
              The range (1, 3) in the 2nd query has 
              [2, 3, -5], since it is prefix, we 
              have to start from 2. Hence, the max
              prefix sum will be 2 + 3 = 5.

Input: a[] = {-2, -3, 4, -1, -2, 1, 5, -3} 
       q = 1
       l = 1 r = 7 

Output: 4

Explanation:- The range (1, 7) in the 1st query has 
              [-3, 4, -1, -2, 1, 5, -3], since it is
              prefix, we have to start from -3. 
              Hence, the max prefix sum will be 
              -3 + 4 - 1 - 2 + 1 + 5 = 4.

Normal Approach:  A simple solution is to run a loop from l to r and calculate max prefix sum from l to r for every query.

C++




#include <bits/stdc++.h>
using namespace std;
int ans(vector<int> arr, int l, int r)
{
    // Calculate prefix sum for current query
    int prefix_sum = 0;
    int max_prefix_sum = INT_MIN;
    for (int i = l; i <= r; i++) {
        prefix_sum += arr[i];
        max_prefix_sum = max(max_prefix_sum, prefix_sum);
    }
    // returning the maximum prefix sum for current query
    return max_prefix_sum;
}
 
int main()
{
    // given array for the question.
    vector<int> arr = { -1, 2, 3, -5 };
    // passing the first querry to the function.
    cout << ans(arr, 0, 3) << endl;
    // passing the 2nd  querry to the function.
    cout << ans(arr, 1, 3) << endl;
 
    return 0;
}
// This code is contributed by Naveen Gujjar


Java




import java.util.*;
 
public class Main {
    public static int ans(List<Integer> arr, int l, int r)
    {
        // Calculate prefix sum for current query
        int prefix_sum = 0;
        int max_prefix_sum = Integer.MIN_VALUE;
        for (int i = l; i <= r; i++) {
            prefix_sum += arr.get(i);
            max_prefix_sum
                = Math.max(max_prefix_sum, prefix_sum);
        }
        // returning the maximum prefix sum for current
        // query
        return max_prefix_sum;
    }
 
    public static void main(String[] args)
    {
        // given array for the question.
        List<Integer> arr = Arrays.asList(-1, 2, 3, -5);
        // passing the first query to the function.
        System.out.println(ans(arr, 0, 3));
        // passing the 2nd query to the function.
        System.out.println(ans(arr, 1, 3));
    }
}


Python3




def ans(arr, l, r):
    # Calculate prefix sum for current query
    prefix_sum = 0
    max_prefix_sum = float('-inf')
    for i in range(l, r+1):
        prefix_sum += arr[i]
        max_prefix_sum = max(max_prefix_sum, prefix_sum)
    # returning the maximum prefix sum for current query
    return max_prefix_sum
 
 
if __name__ == '__main__':
    # given array for the question.
    arr = [-1, 2, 3, -5]
    # passing the first querry to the function.
    print(ans(arr, 0, 3))
    # passing the 2nd  querry to the function.
    print(ans(arr, 1, 3))


C#





Javascript




function ans(arr, l, r) {
  // Calculate prefix sum for current query
  let prefix_sum = 0;
  let max_prefix_sum = -Infinity;
  for (let i = l; i <= r; i++) {
    prefix_sum += arr[i];
    max_prefix_sum = Math.max(max_prefix_sum, prefix_sum);
  }
  // returning the maximum prefix sum for current query
  return max_prefix_sum;
}
 
// given array for the question.
let arr = [-1, 2, 3, -5];
// passing the first querry to the function.
console.log(ans(arr, 0, 3));
// passing the 2nd querry to the function.
console.log(ans(arr, 1, 3));


Output

4
5

Time Complexity: O(q * n), 
Auxiliary Space: O(1)

Efficient Approach: 

An efficient approach will be to build a segment tree where each node stores two values(sum and prefix_sum), and do a range query on it to find the max prefix sum. But for building the segment tree we have to think about what to store on the nodes of the tree. 

For finding out the maximum prefix sum, we will require two things, one being the sum and the other prefix sum. The merging will return two things, sum of the ranges and the prefix sum that will store the max(prefix.left, prefix.sum + prefix.right) in the segment tree.

If we have a deep look into it, the max prefix sum for any two range combining will either be the prefix sum from left side or the sum of left side+prefix sum of right side, whichever is max is taken into account. 

Representation of Segment trees:

  1. Leaf Nodes are the elements of the input array. 
  2. Each internal node represents some merging of the leaf nodes. The merging may be different for different problems. For this problem, merging is sum of leaves under a node.

An array representation of tree is used to represent Segment Trees. For each node at index i, the left child is at index 2*i+1, right child at 2*i+2 and the parent is at (i-1)/2.

Construction of Segment Tree from given array:

We start with a segment arr[0 . . . n-1]. and every time we divide the current segment into two halves(if it has not yet become a segment of length 1), and then call the same procedure on both halves, and for each such segment, we store the sum and prefix sum in corresponding node.

We then do a range query on segment tree to find out the max prefix-sum for the given range, and output the max prefix-sum.

Below is the C++ implementation of above approach. 

CPP




// CPP program to find
// maximum prefix sum
#include <bits/stdc++.h>
using namespace std;
 
// struct two store two values in one node
struct Node {
    int sum;
    int prefix;
};
 
Node tree[4 * 10000];
 
// function to build the segment tree
void build(int a[], int index, int beg, int end)
{
    if (beg == end) {
 
        // If there is one element in array,
        // store it in current node of
        // segment tree
        tree[index].sum = a[beg];
        tree[index].prefix = a[beg];
    } else {
        int mid = (beg + end) / 2;
 
        // If there are more than one elements,
        // then recur for left and right subtrees
        build(a, 2 * index + 1, beg, mid);
        build(a, 2 * index + 2, mid + 1, end);
 
        // adds the sum and stores in the index
        // position of segment tree
        tree[index].sum = tree[2 * index + 1].sum +
                          tree[2 * index + 2].sum;
 
        // stores the max of prefix-sum either
        // from right or from left.
        tree[index].prefix = max(tree[2 * index + 1].prefix,
                                 tree[2 * index + 1].sum +
                                tree[2 * index + 2].prefix);
    }
}
 
// function to do the range query in the segment
// tree for the maximum prefix sum
Node query(int index, int beg, int end, int l, int r)
{
    Node result;
    result.sum = result.prefix = -1;
 
    // If segment of this node is outside the given
    // range, then return the minimum value.
    if (beg > r || end < l)
        return result;
 
    // If segment of this node is a part of given
    // range, then return the node of the segment
    if (beg >= l && end <= r)
        return tree[index];
 
    int mid = (beg + end) / 2;
 
    // if left segment of this node falls out of
    // range, then recur in the right side of
    // the tree
    if (l > mid)
        return query(2 * index + 2, mid + 1, end,
                                         l, r);
 
    // if right segment of this node falls out of
    // range, then recur in the left side of
    // the tree
    if (r <= mid)
        return query(2 * index + 1, beg, mid,
                                       l, r);
 
    // If a part of this segment overlaps with
    // the given range
    Node left = query(2 * index + 1, beg, mid,
                                        l, r);
    Node right = query(2 * index + 2, mid + 1,
                                   end, l, r);
 
    // adds the sum of the left and right
    // segment
    result.sum = left.sum + right.sum;
 
    // stores the max of prefix-sum
    result.prefix = max(left.prefix, left.sum +
                            right.prefix);
 
    // returns the value
    return result;
}
 
// driver program to test the program
int main()
{
 
    int a[] = { -2, -3, 4, -1, -2, 1, 5, -3 };
 
    // calculates the length of array
    int n = sizeof(a) / sizeof(a[0]);
 
    // calls the build function to build
    // the segment tree
    build(a, 0, 0, n - 1);
 
    // find the max prefix-sum between
    // 3rd and 5th index of array
    cout << query(0, 0, n - 1, 3, 5).prefix
         << endl;
 
    // find the max prefix-sum between
    // 0th and 7th index of array
    cout << query(0, 0, n - 1, 1, 7).prefix
         << endl;
 
    return 0;
}


Java




// JAVA program to find
// maximum prefix sum
class GFG
{
 
// two store two values in one node
static class Node
{
    int sum;
    int prefix;
};
 
static Node []tree = new Node[4 * 10000];
static
{
    for(int i = 0; i < tree.length; i++)
        tree[i] = new Node();
}
 
// function to build the segment tree
static void build(int a[], int index, int beg, int end)
{
    if (beg == end)
    {
 
        // If there is one element in array,
        // store it in current node of
        // segment tree
        tree[index].sum = a[beg];
        tree[index].prefix = a[beg];
    } else {
        int mid = (beg + end) / 2;
 
        // If there are more than one elements,
        // then recur for left and right subtrees
        build(a, 2 * index + 1, beg, mid);
        build(a, 2 * index + 2, mid + 1, end);
 
        // adds the sum and stores in the index
        // position of segment tree
        tree[index].sum = tree[2 * index + 1].sum +
                        tree[2 * index + 2].sum;
 
        // stores the max of prefix-sum either
        // from right or from left.
        tree[index].prefix = Math.max(tree[2 * index + 1].prefix,
                                tree[2 * index + 1].sum +
                                tree[2 * index + 2].prefix);
    }
}
 
// function to do the range query in the segment
// tree for the maximum prefix sum
static Node query(int index, int beg, int end, int l, int r)
{
    Node result = new Node();
    result.sum = result.prefix = -1;
 
    // If segment of this node is outside the given
    // range, then return the minimum value.
    if (beg > r || end < l)
        return result;
 
    // If segment of this node is a part of given
    // range, then return the node of the segment
    if (beg >= l && end <= r)
        return tree[index];
 
    int mid = (beg + end) / 2;
 
    // if left segment of this node falls out of
    // range, then recur in the right side of
    // the tree
    if (l > mid)
        return query(2 * index + 2, mid + 1, end,
                                        l, r);
 
    // if right segment of this node falls out of
    // range, then recur in the left side of
    // the tree
    if (r <= mid)
        return query(2 * index + 1, beg, mid,
                                    l, r);
 
    // If a part of this segment overlaps with
    // the given range
    Node left = query(2 * index + 1, beg, mid,
                                        l, r);
    Node right = query(2 * index + 2, mid + 1,
                                end, l, r);
 
    // adds the sum of the left and right
    // segment
    result.sum = left.sum + right.sum;
 
    // stores the max of prefix-sum
    result.prefix = Math.max(left.prefix, left.sum +
                            right.prefix);
 
    // returns the value
    return result;
}
 
// Driver code
public static void main(String[] args)
{
 
    int a[] = { -2, -3, 4, -1, -2, 1, 5, -3 };
 
    // calculates the length of array
    int n = a.length;
 
    // calls the build function to build
    // the segment tree
    build(a, 0, 0, n - 1);
 
    // find the max prefix-sum between
    // 3rd and 5th index of array
    System.out.print(query(0, 0, n - 1, 3, 5).prefix
        +"\n");
 
    // find the max prefix-sum between
    // 0th and 7th index of array
    System.out.print(query(0, 0, n - 1, 1, 7).prefix
        +"\n");
}
}
 
// This code is contributed by PrinciRaj1992


C#




// C# program to find
// maximum prefix sum
using System;
 
class GFG
{
 
// two store two values in one node
class Node
{
    public int sum;
    public int prefix;
};
 
static Node []tree = new Node[4 * 10000];
 
// function to build the segment tree
static void build(int []a, int index, int beg, int end)
{
    if (beg == end)
    {
 
        // If there is one element in array,
        // store it in current node of
        // segment tree
        tree[index].sum = a[beg];
        tree[index].prefix = a[beg];
    } else {
        int mid = (beg + end) / 2;
 
        // If there are more than one elements,
        // then recur for left and right subtrees
        build(a, 2 * index + 1, beg, mid);
        build(a, 2 * index + 2, mid + 1, end);
 
        // adds the sum and stores in the index
        // position of segment tree
        tree[index].sum = tree[2 * index + 1].sum +
                        tree[2 * index + 2].sum;
 
        // stores the max of prefix-sum either
        // from right or from left.
        tree[index].prefix = Math.Max(tree[2 * index + 1].prefix,
                                tree[2 * index + 1].sum +
                                tree[2 * index + 2].prefix);
    }
}
 
// function to do the range query in the segment
// tree for the maximum prefix sum
static Node query(int index, int beg, int end, int l, int r)
{
    Node result = new Node();
    result.sum = result.prefix = -1;
 
    // If segment of this node is outside the given
    // range, then return the minimum value.
    if (beg > r || end < l)
        return result;
 
    // If segment of this node is a part of given
    // range, then return the node of the segment
    if (beg >= l && end <= r)
        return tree[index];
 
    int mid = (beg + end) / 2;
 
    // if left segment of this node falls out of
    // range, then recur in the right side of
    // the tree
    if (l > mid)
        return query(2 * index + 2, mid + 1, end,
                                        l, r);
 
    // if right segment of this node falls out of
    // range, then recur in the left side of
    // the tree
    if (r <= mid)
        return query(2 * index + 1, beg, mid,
                                    l, r);
 
    // If a part of this segment overlaps with
    // the given range
    Node left = query(2 * index + 1, beg, mid,
                                        l, r);
    Node right = query(2 * index + 2, mid + 1,
                                end, l, r);
 
    // adds the sum of the left and right
    // segment
    result.sum = left.sum + right.sum;
 
    // stores the max of prefix-sum
    result.prefix = Math.Max(left.prefix, left.sum +
                            right.prefix);
 
    // returns the value
    return result;
}
 
// Driver code
public static void Main(String[] args)
{
 
    for(int i = 0; i < tree.Length; i++)
        tree[i] = new Node();
    int []a = { -2, -3, 4, -1, -2, 1, 5, -3 };
 
    // calculates the length of array
    int n = a.Length;
 
    // calls the build function to build
    // the segment tree
    build(a, 0, 0, n - 1);
 
    // find the max prefix-sum between
    // 3rd and 5th index of array
    Console.Write(query(0, 0, n - 1, 3, 5).prefix
        +"\n");
 
    // find the max prefix-sum between
    // 0th and 7th index of array
    Console.Write(query(0, 0, n - 1, 1, 7).prefix
        +"\n");
}
}
 
// This code is contributed by Rajput-Ji


Python3




# Python3 program to find
# maximum prefix sum
 
# struct two store two values in one node
 
# function to build the segment tree
def build(a, index, beg, end):
    global tree
 
    if (beg == end):
 
        # If there is one element in array,
        # store it in current node of
        # segment tree
        tree[index][0] = a[beg]
        tree[index][1] = a[beg]
    else:
        mid = (beg + end) // 2
 
        # If there are more than one elements,
        # then recur for left and right subtrees
        build(a, 2 * index + 1, beg, mid)
        build(a, 2 * index + 2, mid + 1, end)
 
        # adds the sum and stores in the index
        # position of segment tree
        tree[index][0] = tree[2 * index + 1][0] + tree[2 * index + 2][0]
 
        # stores the max of prefix-sum either
        # from right or from left.
        tree[index][1] = max(tree[2 * index + 1][1],tree[2 * index + 1][0] + tree[2 * index + 2][1])
 
# function to do the range query in the segment
# tree for the maximum prefix sum
def query(index, beg, end, l, r):
    global tree
    result = [-1, -1]
    # result[0] = result[1] = -1
 
    # If segment of this node is outside the given
    # range, then return the minimum value.
    if (beg > r or end < l):
        return result
 
    # If segment of this node is a part of given
    # range, then return the node of the segment
    if (beg >= l and end <= r):
        return tree[index]
 
    mid = (beg + end) // 2
 
    # if left segment of this node falls out of
    # range, then recur in the right side of
    # the tree
    if (l > mid):
        return query(2 * index + 2, mid + 1, end, l, r)
 
    # if right segment of this node falls out of
    # range, then recur in the left side of
    # the tree
    if (r <= mid):
        return query(2 * index + 1, beg, mid, l, r)
 
    # If a part of this segment overlaps with
    # the given range
    left = query(2 * index + 1, beg, mid, l, r)
    right = query(2 * index + 2, mid + 1, end, l, r)
 
    # adds the sum of the left and right
    # segment
    result[0] = left[0] + right[0]
 
    # stores the max of prefix-sum
    result[1] = max(left[1], left[0] + right[1])
 
    # returns the value
    return result
 
 
# driver program to test the program
if __name__ == '__main__':
 
    a = [-2, -3, 4, -1, -2, 1, 5, -3 ]
 
    tree = [[0,0] for i in range(4 * 10000)]
 
    # calculates the length of array
    n = len(a)
 
    # calls the build function to build
    # the segment tree
    build(a, 0, 0, n - 1)
 
    # find the max prefix-sum between
    # 3rd and 5th index of array
    print(query(0, 0, n - 1, 3, 5)[1])
 
    # find the max prefix-sum between
    # 0th and 7th index of array
    print(query(0, 0, n - 1, 1, 7)[1])
 
    # This code is contributed by mohit kumar 29.


Javascript




<script>
 
// JavaScript program to find
// maximum prefix sum
     
    // two store two values in one node
    class Node
    {
        constructor()
        {
            let sum,prefix;
        }
    }
     
    let tree=new Array(4 * 10000);
    for(let i = 0; i < tree.length; i++)
        tree[i] = new Node();
     
    // function to build the segment tree
    function build(a,index,beg,end)
    {
        if (beg == end)
    {
  
        // If there is one element in array,
        // store it in current node of
        // segment tree
        tree[index].sum = a[beg];
        tree[index].prefix = a[beg];
    } else {
        let mid = Math.floor((beg + end) / 2);
  
        // If there are more than one elements,
        // then recur for left and right subtrees
        build(a, 2 * index + 1, beg, mid);
        build(a, 2 * index + 2, mid + 1, end);
  
        // adds the sum and stores in the index
        // position of segment tree
        tree[index].sum = tree[2 * index + 1].sum +
                        tree[2 * index + 2].sum;
  
        // stores the max of prefix-sum either
        // from right or from left.
        tree[index].prefix =
        Math.max(tree[2 * index + 1].prefix,
        tree[2 * index + 1].sum +
        tree[2 * index + 2].prefix);
    }
    }
     
    // function to do the range query in the segment
// tree for the maximum prefix sum
    function query(index,beg,end,l,r)
    {
        let result = new Node();
    result.sum = result.prefix = -1;
  
    // If segment of this node is outside the given
    // range, then return the minimum value.
    if (beg > r || end < l)
        return result;
  
    // If segment of this node is a part of given
    // range, then return the node of the segment
    if (beg >= l && end <= r)
        return tree[index];
  
    let mid = Math.floor((beg + end) / 2);
  
    // if left segment of this node falls out of
    // range, then recur in the right side of
    // the tree
    if (l > mid)
        return query(2 * index + 2, mid + 1, end,
                                        l, r);
  
    // if right segment of this node falls out of
    // range, then recur in the left side of
    // the tree
    if (r <= mid)
        return query(2 * index + 1, beg, mid,
                                    l, r);
  
    // If a part of this segment overlaps with
    // the given range
    let left = query(2 * index + 1, beg, mid,
                                        l, r);
    let right = query(2 * index + 2, mid + 1,
                                end, l, r);
  
    // adds the sum of the left and right
    // segment
    result.sum = left.sum + right.sum;
  
    // stores the max of prefix-sum
    result.prefix = Math.max(left.prefix, left.sum +
                            right.prefix);
  
    // returns the value
    return result;
    }
     
     
    // Driver code
    let a=[-2, -3, 4, -1, -2, 1, 5, -3];
    // calculates the length of array
    let n = a.length;
  
    // calls the build function to build
    // the segment tree
    build(a, 0, 0, n - 1);
  
    // find the max prefix-sum between
    // 3rd and 5th index of array
    document.write(query(0, 0, n - 1, 3, 5).prefix
        +"<br>");
  
    // find the max prefix-sum between
    // 0th and 7th index of array
    document.write(query(0, 0, n - 1, 1, 7).prefix
        +"<br>");
     
 
// This code is contributed by patel2127
 
</script>


Output

-1
4

Time Complexity: 

Time Complexity for tree construction is O(n). There are total 2n-1 nodes, and value of every node is calculated only once in tree construction.
Time complexity to every query is O(log n).
Time complexity for the problem is O(q * log n)

Space Complexity: O(n)

 



Last Updated : 27 Mar, 2023
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads