Hello Everyone,
Given an array of Integers and an Integer value k, find out k sub-arrays(may be overlapping), which have k maximum sums.
Method for k-maximum sub-arrays:
- 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++ 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;
}
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) .