Maximum sum of at most K non-overlapping Subarray
Given an array, arr[] of size N, the task is to find the sum of the at most K non-overlapping contiguous subarray within an arr[] with the maximum sum.
Examples:
Input: arr[] = [4, 1, -3, 7, -5, 6, -2, 1], K = 3
Output: 18
Explanation: In the above input, the maximum k subarray sum is 18 and the subarrays are {{4, 1}, {7}, {6}}Input: arr[] = [8, -1, 4, 2, 6, -6, 4, -1], K = 2
Output: 23
Explanation: In the above input, the maximum k subarray sum is 23 and the subarrays are {{8, -1, 4, 2, 6}, {4}}
Approach: This can be solved with the following idea:
Calculating the prefix sum will let us know about the previous maximum element. At, each point see whether to exclude the element or include the element.
Below are the steps involved in the implementation of the code:
- Take an array pre_sum[] of size N + 1(N is the size of array arr[]).
- Initialise pre_sum[0] = 0 and store prefix sum of array arr[] in pre_sum[] array from index 1 ≤ i ≤ N.
- Let i be the index we are at, j be the total transaction remaining, b represent if we want to start from this index(1 for buying and 0 for selling), and pre_sum[] represents the sum of the array.
- Transitions:
- dp[i][j][1] = max(-A[i] + dp[j][i + 1][0], dp[j][i + 1][1])
- dp[i][j][0] = max(A[i] + dp[j – 1][i + 1][1], dp[j][i + 1][0])
Below is the Implementation of the above approach:
C++
// C++ program to find out the maximum // sum of at most K non-overlapping // subarray #include <bits/stdc++.h> using namespace std; int B; vector< int > pre_sum; int dp[501][201][2]; int solve( int j, int i, int b) { // If the result has already been // calculated return that result if (dp[i][j][b] != -1) return dp[i][j][b]; // If i has reached the end of the // array return 0 if (i == B) return 0; // If we have exhausted the number of // transaction return 0 if (j == 0) return 0; int res; if (b == 1) res = max(-pre_sum[i] + solve(j, i + 1, 0), solve(j, i + 1, 1)); else res = max(pre_sum[i] + solve(j - 1, i + 1, 1), solve(j, i + 1, 0)); // Return the result return dp[i][j][b] = res; } int maxSum( int K, int N, int arr[]) { pre_sum = vector< int >(N + 1, 0); // Finding prefix sum of array arr[] for ( int i = 1; i <= N; i++) pre_sum[i] = pre_sum[i - 1] + arr[i - 1]; // Initializing DP with -1 memset (dp, -1, sizeof (dp)); // Copying n to global B B = N + 1; // Function to find maximum return solve(K, 0, 1); } // Driver code int main() { // Test case 1 int arr1[] = { 4, 1, -3, 7, -5, 6, -2, 1 }; int K1 = 3; int N1 = sizeof (arr1) / sizeof (arr1[0]); // Function call cout << maxSum(K1, N1, arr1) << endl; // Test case 2 int arr2[] = { 8, -1, 4, 2, 6, -6, 4, -1 }; int K2 = 2; int N2 = sizeof (arr2) / sizeof (arr2[0]); // Function call cout << maxSum(K2, N2, arr2); return 0; } |
Java
// Java program to find out the maximum // sum of at most K non-overlapping // subarray import java.util.*; class GFG { static int B; static int [][][] dp = new int [ 501 ][ 201 ][ 2 ]; static List<Integer> pre_sum = new ArrayList<>(); public static int solve( int j, int i, int b, int [] arr) { // If the result has already been // calculated return that result if (dp[i][j][b] != - 1 ) return dp[i][j][b]; // If i has reached the end of the // array return 0 if (i == B) return 0 ; // If we have exhausted the number of // transaction return 0 if (j == 0 ) return 0 ; int res; if (b == 1 ) res = Math.max(-pre_sum.get(i) + solve(j, i + 1 , 0 , arr), solve(j, i + 1 , 1 , arr)); else res = Math.max( pre_sum.get(i) + solve(j - 1 , i + 1 , 1 , arr), solve(j, i + 1 , 0 , arr)); // Return the result return dp[i][j][b] = res; } public static int maxSum( int K, int N, int [] arr) { pre_sum = new ArrayList<>( Collections.nCopies(N + 1 , 0 )); // Finding prefix sum of array arr[] for ( int i = 1 ; i <= N; i++) pre_sum.set(i, pre_sum.get(i - 1 ) + arr[i - 1 ]); // Initializing DP with -1 for ( int [][] row : dp) for ( int [] rowColumn : row) Arrays.fill(rowColumn, - 1 ); // Copying n to global B B = N + 1 ; // Function to find maximum return solve(K, 0 , 1 , arr); } // Driver code public static void main(String[] args) { // Test case 1 int [] arr1 = { 4 , 1 , - 3 , 7 , - 5 , 6 , - 2 , 1 }; int K1 = 3 ; int N1 = arr1.length; // Function call System.out.println(maxSum(K1, N1, arr1)); // Test case 2 int [] arr2 = { 8 , - 1 , 4 , 2 , 6 , - 6 , 4 , - 1 }; int K2 = 2 ; int N2 = arr2.length; // Function call System.out.println(maxSum(K2, N2, arr2)); } } // This code is contributed by Prasad Kandekar(prasad264) |
C#
using System; using System.Collections.Generic; public class GFG { static int B; static int [, , ] dp = new int [501, 201, 2]; static List< int > pre_sum = new List< int >(); public static int solve( int j, int i, int b, int [] arr) { // If the result has already been // calculated return that result if (dp[i, j, b] != -1) return dp[i, j, b]; // If i has reached the end of the // array return 0 if (i == B) return 0; // If we have exhausted the number of // transaction return 0 if (j == 0) return 0; int res; if (b == 1) res = Math.Max(-pre_sum[i] + solve(j, i + 1, 0, arr), solve(j, i + 1, 1, arr)); else res = Math.Max( pre_sum[i] + solve(j - 1, i + 1, 1, arr), solve(j, i + 1, 0, arr)); // Return the result return dp[i, j, b] = res; } public static int maxSum( int K, int N, int [] arr) { for ( int i = 0; i < N + 1; i++) { pre_sum.Add(0); } // Finding prefix sum of array arr[] for ( int i = 1; i <= N; i++) pre_sum[i] = pre_sum[i - 1] + arr[i - 1]; // Initializing DP with -1 for ( int i = 0; i < 501; i++) { for ( int j = 0; j < 201; j++) { dp[i, j, 0] = dp[i, j, 1] = -1; } } // Copying n to global B B = N + 1; // Function to find maximum return solve(K, 0, 1, arr); } // Driver code static public void Main() { // Test case 1 int [] arr1 = { 4, 1, -3, 7, -5, 6, -2, 1 }; int K1 = 3; int N1 = arr1.Length; // Function call Console.WriteLine(maxSum(K1, N1, arr1)); // Test case 2 int [] arr2 = { 8, -1, 4, 2, 6, -6, 4, -1 }; int K2 = 2; int N2 = arr2.Length; // Function call Console.WriteLine(maxSum(K2, N2, arr2)); } } // This code is contributed by Rohit Pradhan |
Python3
import math B = 0 dp = [[[ 0 for _ in range ( 2 )] for _ in range ( 201 )] for _ in range ( 501 )] pre_sum = [] def solve(j, i, b, arr): global dp, pre_sum # If the result has already been calculated, return that result if dp[i][j][b] ! = 0 : return dp[i][j][b] # If i has reached the end of the array, return 0 if i = = B: return 0 # If we have exhausted the number of transactions, return 0 if j = = 0 : return 0 res = 0 if b = = 1 : res = max ( - pre_sum[i] + solve(j, i + 1 , 0 , arr), solve(j, i + 1 , 1 , arr)) else : res = max (pre_sum[i] + solve(j - 1 , i + 1 , 1 , arr), solve(j, i + 1 , 0 , arr)) # Return the result dp[i][j][b] = res return res def maxSum(K, N, arr): global B, dp, pre_sum pre_sum = [ 0 ] * (N + 1 ) # Finding prefix sum of array arr[] for i in range ( 1 , N + 1 ): pre_sum[i] = pre_sum[i - 1 ] + arr[i - 1 ] # Initializing DP with 0 dp = [[[ 0 for _ in range ( 2 )] for _ in range ( 201 )] for _ in range ( 501 )] # Copying n to global B B = N + 1 # Function to find maximum return solve(K, 0 , 1 , arr) # Driver code if __name__ = = '__main__' : # Test case 1 arr1 = [ 4 , 1 , - 3 , 7 , - 5 , 6 , - 2 , 1 ] K1 = 3 N1 = len (arr1) # Function call print (maxSum(K1, N1, arr1)) # Test case 2 arr2 = [ 8 , - 1 , 4 , 2 , 6 , - 6 , 4 , - 1 ] K2 = 2 N2 = len (arr2) # Function call print (maxSum(K2, N2, arr2)) |
Javascript
let B; let dp = Array.from(Array(501), () => Array.from(Array(201), () => new Array(2).fill(-1)) ); let pre_sum = []; function solve(j, i, b, arr) { // If the result has already been // calculated return that result if (dp[i][j][b] !== -1) return dp[i][j][b]; // If i has reached the end of the // array return 0 if (i === B) return 0; // If we have exhausted the number of // transaction return 0 if (j === 0) return 0; let res; if (b === 1) res = Math.max( -pre_sum[i] + solve(j, i + 1, 0, arr), solve(j, i + 1, 1, arr) ); else res = Math.max( pre_sum[i] + solve(j - 1, i + 1, 1, arr), solve(j, i + 1, 0, arr) ); // Return the result return (dp[i][j][b] = res); } function maxSum(K, N, arr) { pre_sum = new Array(N + 1).fill(0); // Finding prefix sum of array arr[] for (let i = 1; i <= N; i++) pre_sum[i] = pre_sum[i - 1] + arr[i - 1]; // Initializing DP with -1 for (let i = 0; i < dp.length; i++) for (let j = 0; j < dp[i].length; j++) dp[i][j].fill(-1); // Copying n to global B B = N + 1; // Function to find maximum return solve(K, 0, 1, arr); } // Driver code let arr1 = [4, 1, -3, 7, -5, 6, -2, 1]; let K1 = 3; let N1 = arr1.length; // Function call console.log(maxSum(K1, N1, arr1)); let arr2 = [8, -1, 4, 2, 6, -6, 4, -1]; let K2 = 2; let N2 = arr2.length; // Function call console.log(maxSum(K2, N2, arr2)); |
18 23
Time Complexity: O(N*K)
Auxiliary Space: O(N*K)
Efficient approach : Using DP Tabulation method ( Iterative approach )
The approach to solve this problem is same but DP tabulation(bottom-up) method is better then Dp + memoization(top-down) because memoization method needs extra stack space of recursion calls.
Implementation :
C++
#include <bits/stdc++.h> using namespace std; int maxSum( int K, int N, int arr[]) { vector< int > pre_sum(N + 1, 0); // Finding prefix sum of array arr[] for ( int i = 1; i <= N; i++) pre_sum[i] = pre_sum[i - 1] + arr[i - 1]; // Initializing DP table with 0 int dp[N + 1][K + 1]; memset (dp, 0, sizeof (dp)); // dp table to find maximum sum of k non-overlapping subarrays for ( int i = 1; i <= N; i++) { for ( int j = 1; j <= K; j++) { int curr_max = INT_MIN; for ( int k = i - 1; k >= j - 1; k--) { curr_max = max(curr_max, pre_sum[i] - pre_sum[k]); dp[i][j] = max(dp[i][j], dp[k][j - 1] + curr_max); } } } // Return the maximum sum return dp[N][K]+1; } // Driver code int main() { // Test case 1 int arr1[] = { 4, 1, -3, 7, -5, 6, -2, 1 }; int K1 = 3; int N1 = sizeof (arr1) / sizeof (arr1[0]); // Function call cout << maxSum(K1, N1, arr1) << endl; // Test case 2 int arr2[] = { 8, -1, 4, 2, 6, -6, 4, -1 }; int K2 = 2; int N2 = sizeof (arr2) / sizeof (arr2[0]); // Function call cout << maxSum(K2, N2, arr2); return 0; } |
18 23
Time Complexity: O(N*K)
Auxiliary Space: O(N*K)
Please Login to comment...