Thursday, December 26, 2024
Google search engine
HomeLanguagesDynamic ProgrammingK maximum sums of overlapping contiguous sub-arrays

K maximum sums of overlapping contiguous sub-arrays

Given an array of Integers and an Integer value k, find out k sub-arrays(may be overlapping), which have k maximum sums. Examples:

Input : arr = {4, -8, 9, -4, 1, -8, -1, 6}, k = 4
Output : 9 6 6 5
Input : arr = {-2, -3, 4, -1, -2, 1, 5, -3}, k= 3
Output : 7 6 5

Using Kadane’s Algorithm we can find the maximum contiguous subarray sum of an array. But in the case Kadane’s Algorithm does not work. As whenever we hit an negative number in the array we set the max_ending_here variable to zero, hence we miss the possibilities for second and so on maximums. Here we use an algorithm presented by Sung Eun Bae and Tadao Takaoka which computes the maximum sub-array sum problem in O(n) time and k maximum sub-array sum problem in O(k*n) time. First we look at the problem of only maximum sub-array sum using this method: Prerequisite: 1. Prefix sum array 2. Maximum subarray sum in O(n) using prefix sum Method for k-maximum sub-arrays:

1. Calculate the prefix sum of the input array.
2. Take cand, maxi and mini as arrays of size k. 
3. Initialize mini[0] = 0 for the same reason as previous.
4. for each value of the prefix_sum[i] do
       (i). update cand[j] value by prefix_sum[i] - mini[j]
       (ii). maxi will be the maximum k elements of maxi and cand
       (iii). if prefix_sum is less than all values of mini, then 
              include it in mini and remove the maximum element from mini
       // After the ith iteration mini holds k minimum prefix sum upto
       // index i and maxi holds k maximum overlapping sub-array sums 
       // upto index i.
5. return maxi 

Throughout this calculation method, we keep maxi in non-increasing and mini in non-decreasing order. 

C++




// C++ program to find out k maximum sum of
// overlapping sub-arrays
#include <iostream>
#include <limits>
#include <vector>
 
using namespace std;
 
// Function to compute prefix-sum of the input array
vector<int> prefix_sum(vector<int> arr, int n)
{
    vector<int> pre_sum;
    pre_sum.push_back(arr[0]);
    for (int i = 1; i < n; i++)
        pre_sum.push_back(pre_sum[i - 1] + arr[i]);   
    return pre_sum;
}
 
// Update maxi by k maximum values from maxi and cand
void maxMerge(vector<int>& maxi, vector<int> cand)
{
    // Here cand and maxi arrays are in non-increasing
    // order beforehand. Now, j is the index of the
    // next cand element and i is the index of next
    // maxi element. Traverse through maxi array.
    // If cand[j] > maxi[i] insert cand[j] at the ith
    // position in the maxi array and remove the minimum
    // element of the maxi array i.e. the last element
    // and increase j by 1 i.e. take the next element
    // from cand.
    int k = maxi.size();
    int j = 0;
    for (int i = 0; i < k; i++) {
        if (cand[j] > maxi[i]) {
            maxi.insert(maxi.begin() + i, cand[j]);
            maxi.erase(maxi.begin() + k);
            j += 1;
        }
    }
}
 
// Insert prefix_sum[i] to mini array if needed
void insertMini(vector<int>& mini, int pre_sum)
{
    // Traverse the mini array from left to right.
    // If prefix_sum[i] is less than any element
    // then insert prefix_sum[i] at that position
    // and delete maximum element of the mini array
    // i.e. the rightmost element from the array.
    int k = mini.size();
    for (int i = 0; i < k; i++) {
        if (pre_sum < mini[i]) {
            mini.insert(mini.begin() + i, pre_sum);
            mini.erase(mini.begin() + k);
            break;
        }
    }
}
 
// Function to compute k maximum overlapping sub-
// array sums
void kMaxOvSubArray(vector<int> arr, int k)
{
    int n = arr.size();
 
    // Compute the prefix sum of the input array.
    vector<int> pre_sum = prefix_sum(arr, n);
 
    // Set all the elements of mini as +infinite
    // except 0th. Set the 0th element as 0.
    vector<int> mini(k, numeric_limits<int>::max());
    mini[0] = 0;
 
    // Set all the elements of maxi as -infinite.
    vector<int> maxi(k, numeric_limits<int>::min());
 
    // Initialize cand array.
    vector<int> cand(k);
 
    // For each element of the prefix_sum array do:
    // compute the cand array.
    // take k maximum values from maxi and cand
    // using maxmerge function.
    // insert prefix_sum[i] to mini array if needed
    // using insertMini function.
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < k; j++) {
             if(pre_sum[i] < 0 && mini[j]==numeric_limits<int>::max())
           cand[j]=(-pre_sum[i])-mini[j];
         else cand[j] = pre_sum[i] - mini[j];
        }
        maxMerge(maxi, cand);
        insertMini(mini, pre_sum[i]);
    }
 
    // Elements of maxi array is the k
    // maximum overlapping sub-array sums.
    // Print out the elements of maxi array.
    for (int ele : maxi)
        cout << ele << " ";
    cout << endl;
}
 
// Driver Program
int main()
{
    // Test case 1
    vector<int> arr1 = { 4, -8, 9, -4, 1, -8, -1, 6 };
    int k1 = 4;
    kMaxOvSubArray(arr1, k1);
 
    // Test case 2
    vector<int> arr2 = { -2, -3, 4, -1, -2, 1, 5, -3 };
    int k2 = 3;
    kMaxOvSubArray(arr2, k2);
    return 0;
}


Java




// Java program to find out k maximum sum of
// overlapping sub-arrays
 
import java.util.ArrayList;
 
class KthMaxSumOverlappingListVersion {
    public static void main(String[] args)
    {
        int[] ab = { 4, -8, 9, -4, 1, -8, -1, 6 };
        int[] aa = { -2, -3, 4, -1, -2, 1, 5, -3 };
          kthMaxSumOverlapping(ab, ab.length, 4);
          System.out.println();
        kthMaxSumOverlapping(aa, aa.length, 3);
    }
 
    // Here cand and maxi arrays are in non-increasing
    // order beforehand. Now, j is the index of the
    // next cand element and i is the index of next
    // maxi element. Traverse through maxi array.
    // If cand[j] > maxi[i] insert cand[j] at the ith
    // position in the maxi array and remove the minimum
    // element of the maxi array i.e. the last element
    // and increase j by 1 i.e. take the next element
    // from cand.
    static void maxMerge(ArrayList<Integer> max,
                         ArrayList<Integer> cand)
    {
        int k = max.size();
        int j = 0;
        for (int i = 0; i < k; i++) {
            if (cand.get(j) > max.get(i)) {
                max.add(i, cand.get(j));
                max.remove(k);
                j++;
            }
        }
    }
 
    // Traverse the mini array from left to right.
    // If prefix_sum[i] is less than any element
    // then insert prefix_sum[i] at that position
    // and delete maximum element of the min
    // i.e. the rightmost element from the min.
    static void minMerge(ArrayList<Integer> min, int ms)
    {
        for (int i = 0; i < min.size(); i++) {
            if (min.get(i) > ms) {
                min.add(i, ms);
                min.remove(min.size() - 1);
                break;
            }
        }
    }
 
    static void kthMaxSumOverlapping(int[] aa, int n, int k)
    {
        ArrayList<Integer> max = new ArrayList<Integer>();
        ArrayList<Integer> min = new ArrayList<Integer>();
        ArrayList<Integer> cand = new ArrayList<Integer>();
        int[] prefixSum = new int[n];
        prefixSum[0] = aa[0];
        for (int i = 1; i < n; i++)
            prefixSum[i] = prefixSum[i - 1] + aa[i];
        for (int i = 0; i < k; i++) {
            max.add(Integer.MIN_VALUE);
            min.add(Integer.MAX_VALUE);
        }
        min.add(0, 0);
        min.remove(k);
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < k; j++) {
                cand.add(prefixSum[i] - min.get(j));
            }
            maxMerge(max, cand);
            minMerge(min, prefixSum[i]);
            cand.clear();
        }
 
        for (int i = 0; i < k; i++) {
            System.out.print(max.get(i) + " ");
        }
    }
}


Python3




# Python program to find out k maximum sum of
# overlapping sub-arrays
 
# Function to compute prefix-sum of the input array
def prefix_sum(arr, n):
    pre_sum = list()
    pre_sum.append(arr[0])
    for i in range(1, n):
        pre_sum.append(pre_sum[i-1] + arr[i])
    return pre_sum
 
# Update maxi by k maximum values from maxi and cand
def maxMerge(maxi, cand):
 
    # Here cand and maxi arrays are in non-increasing
    # order beforehand. Now, j is the index of the
    # next cand element and i is the index of next
    # maxi element. Traverse through maxi array.
    # If cand[j] > maxi[i] insert cand[j] at the ith
    # position in the maxi array and remove the minimum
    # element of the maxi array i.e. the last element
    # and increase j by 1 i.e. take the next element
    # from cand.
    k = len(maxi)
    j = 0
    for i in range(k):
        if (cand[j] > maxi[i]):
            maxi.insert(i, cand[j])
            del maxi[-1]
            j += 1
 
# Insert prefix_sum[i] to mini array if needed
def insertMini(mini, pre_sum):
 
    # Traverse the mini array from left to right.
    # If prefix_sum[i] is less than any element
    # then insert prefix_sum[i] at that position
    # and delete maximum element of the mini array
    # i.e. the rightmost element from the array.
    k = len(mini)
    for i in range(k):
        if (pre_sum < mini[i]):
            mini.insert(i, pre_sum)
            del mini[-1]
            break
 
# Function to compute k maximum overlapping sub-array sums
def kMaxOvSubArray(arr, k):
    n = len(arr)
 
    # Compute the prefix sum of the input array.
    pre_sum = prefix_sum(arr, n)
 
    # Set all the elements of mini as + infinite
    # except 0th. Set the 0th element as 0.
    mini = [float('inf') for i in range(k)]
    mini[0] = 0
 
    # Set all the elements of maxi as -infinite.
    maxi = [-float('inf') for i in range(k)]
 
    # Initialize cand array.
    cand = [0 for i in range(k)]
 
    # For each element of the prefix_sum array do:
    # compute the cand array.
    # take k maximum values from maxi and cand
    # using maxmerge function.
    # insert prefix_sum[i] to mini array if needed
    # using insertMini function.
    for i in range(n):
        for j in range(k):
            cand[j] = pre_sum[i] - mini[j]
        maxMerge(maxi, cand)
        insertMini(mini, pre_sum[i])
 
    # Elements of maxi array is the k
    # maximum overlapping sub-array sums.
    # Print out the elements of maxi array.
    for ele in maxi:
        print(ele, end = ' ')
    print('')
 
# Driver Program
# Test case 1
arr1 = [4, -8, 9, -4, 1, -8, -1, 6]
k1 = 4
kMaxOvSubArray(arr1, k1)
 
# Test case 2
arr2 = [-2, -3, 4, -1, -2, 1, 5, -3]
k2 = 3
kMaxOvSubArray(arr2, k2)


Javascript




<script>
// Javascript program to find out k maximum sum of overlapping sub-arrays
//  Function to compute prefix-sum of the input array
function prefix_sum(arr, n){
    var pre_sum = [];
    pre_sum.push(arr[0]);
    for(var i = 1; i < n; i++)
        pre_sum.push(pre_sum[i-1] + arr[i]);
    return pre_sum;
}
 
// Update maxi by k maximum values from maxi and cand
function maxMerge(maxi, cand){
 
    //  Here cand and maxi arrays are in non-increasing
    //  order beforehand. Now, j is the index of the
    //  next cand element and i is the index of next
    //  maxi element. Traverse through maxi array.
    //  If cand[j] > maxi[i] insert cand[j] at the ith
    //  position in the maxi array and remove the minimum
    //  element of the maxi array i.e. the last element
    //  and increase j by 1 i.e. take the next element
    //  from cand.
    var k = maxi.length;
    var j = 0;
    for(var i = 0; i < k; i++){
        if (cand[j] > maxi[i]){
            maxi.splice(i,0, cand[j]);
            maxi.pop();
            j += 1;
        }
    }
}
//  Insert prefix_sum[i] to mini array if needed
function insertMini(mini, pre_sum){
 
    //  Traverse the mini array from left to right.
    //  If prefix_sum[i] is less than any element
    //  then insert prefix_sum[i] at that position
    //  and delete maximum element of the mini array
    //  i.e. the rightmost element from the array.
    k = mini.length;
    for (var i = 0; i < k; i++){
        if (pre_sum < mini[i]){
            mini.splice(i,0, pre_sum);
            mini.pop();
            break;
        }
    }
}
//  Function to compute k maximum overlapping sub-array sums
function kMaxOvSubArray(arr, k){
    n = arr.length;
 
    //  Compute the prefix sum of the input array.
    pre_sum = prefix_sum(arr, n);
    // console.log(pre_sum);
    //  Set all the elements of mini as + infinite
    //  except 0th. Set the 0th element as 0.
    mini = [];
    for(var i = 0; i < k;i++){
        mini.push(Infinity);
    }
    mini[0] = 0;
 
    //  Set all the elements of maxi as -infinite.
    maxi = [];
    for( i = 0; i < k;i++){
        maxi.push(-Infinity);
    }
 
    //  Initialize cand array.
    cand = [];
    for( i = 0; i < k;i++){
        mini.push(0);
    }
    //  For each element of the prefix_sum array do:
    //  compute the cand array.
    //  take k maximum values from maxi and cand
    //  using maxmerge function.
    //  insert prefix_sum[i] to mini array if needed
    //  using insertMini function.
    for(i = 0; i < n;i++){
        for (var j = 0; j < k ;j++)
            cand[j] = pre_sum[i] - mini[j];
        maxMerge(maxi, cand);
        insertMini(mini, pre_sum[i]);
    }
    //  Elements of maxi array is the k
    //  maximum overlapping sub-array sums.
    //  Print out the elements of maxi array.
    for( i = 0; i < maxi.length;i++){
        document.write(maxi[i]+" ");
    }
    document.write("\n");
}
 
//  Driver Program
// Test case 1
arr1 = [4, -8, 9, -4, 1, -8, -1, 6];
k1 = 4;
kMaxOvSubArray(arr1, k1);
 
//  Test case 2
arr2 = [-2, -3, 4, -1, -2, 1, 5, -3];
k2 = 3;
kMaxOvSubArray(arr2, k2);
 
// This code is contributed by repakaeswaripriya.
</script>


C#




// c# program to find out k maximum sum of
// overlapping sub-arrays
using System;
using System.Collections.Generic;
 
class KthMaxSumOverlappingListVersion
{
static void Main(string[] args)
{
int[] ab = { 4, -8, 9, -4, 1, -8, -1, 6 };
int[] aa = { -2, -3, 4, -1, -2, 1, 5, -3 };
kthMaxSumOverlapping(ab, ab.Length, 4);
Console.WriteLine();
kthMaxSumOverlapping(aa, aa.Length, 3);
}
   // Here cand and maxi arrays are in non-increasing
    // order beforehand. Now, j is the index of the
    // next cand element and i is the index of next
    // maxi element. Traverse through maxi array.
    // If cand[j] > maxi[i] insert cand[j] at the ith
    // position in the maxi array and remove the minimum
    // element of the maxi array i.e. the last element
    // and increase j by 1 i.e. take the next element
    // from cand.
   
 static void maxMerge(List<int> max, List<int> cand)
{
    int k = max.Count;
    int j = 0;
    for (int i = 0; i < k; i++)
    {
        if (cand[j] > max[i])
        {
            max.Insert(i, cand[j]);
            max.RemoveAt(k);
            j++;
        }
    }
}
// Traverse the mini array from left to right.
    // If prefix_sum[i] is less than any element
    // then insert prefix_sum[i] at that position
    // and delete maximum element of the min
    // i.e. the rightmost element from the min.
static void minMerge(List<int> min, int ms)
{
    for (int i = 0; i < min.Count; i++)
    {
        if (min[i] > ms)
        {
            min.Insert(i, ms);
            min.RemoveAt(min.Count - 1);
            break;
        }
    }
}
 
static void kthMaxSumOverlapping(int[] aa, int n, int k)
{
    List<int> max = new List<int>();
    List<int> min = new List<int>();
    List<int> cand = new List<int>();
    int[] prefixSum = new int[n];
    prefixSum[0] = aa[0];
    for (int i = 1; i < n; i++)
        prefixSum[i] = prefixSum[i - 1] + aa[i];
    for (int i = 0; i < k; i++)
    {
        max.Add(int.MinValue);
        min.Add(int.MaxValue);
    }
    min.Insert(0, 0);
    min.RemoveAt(k);
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < k; j++)
        {
            cand.Add(prefixSum[i] - min[j]);
        }
        maxMerge(max, cand);
        minMerge(min, prefixSum[i]);
        cand.Clear();
    }
    for (int i = 0; i < k; i++)
    {
        Console.Write(max[i] + " ");
    }
}
}


Output

9 6 6 5 
7 6 5 

Time Complexity: The ‘insertMini’ and ‘maxMerge’ functions runs in O(k) time and it takes O(k) time to update the ‘cand’ array. We do this process for n times. Hence, the overall time complexity is O(k*n).

Auxiliary Space: O(n)

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 neveropen!

RELATED ARTICLES

Most Popular

Recent Comments