CSES Solutions - Maximum Subarray Sum II
Last Updated : 23 Mar, 2024
Given an array arr[] of N integers, your task is to find the maximum sum of values in a contiguous subarray with length between A and B.
Examples:
Input: N = 8, A = 1, B = 2, arr[] = {-1, 3, -2, 5, 3, -5, 2, 2}
Output: 8
Explanation: The subarray with maximum sum is {5, 3}, the length between 1 and 2, and the sum is 8.
Input: N = 8, A = 1, B = 1, arr[] = {-1, 3, -2, 5, 3, -5, 2, 2}
Output: 5
Explanation: The subarray with maximum sum is {5} with length between 1 and 1, and the sum is 5.
Approach: To solve the problem, follow the below idea:
The idea is to calculate the prefix sum of the given array and calculate the maximum subarray sum, with length being between a and b for each subarray starting at index i. To calculate the maximum subarray sum starting at index i, will be: max(prefixSum[i+a-1] ....... prefixSum[i+b-1]) - prefixSum[i-1], i.e., we need to pick the maximum value from the prefixSum array from the index (i+a-1) to (i+b-1) and subtract prefixSum[i-1] from it, this gives the maximum subarray starting from index i and the length being between a and b. The final answer will be the maximum value among all possible starting index i from 1 to (n-a).
To find the maximum value in the range for each starting index i, it can be observed that window size will be constant which is (b-a+1). So, we can use a deque to maintain the maximum value for each window. You can refer to this article for more details: Sliding Window Maximum (Maximum of all subarrays of size K)
Step-by-step algorithm:
- Initialize a prefixSum[] array of size n+1 to store the cumulative sum of the given array and Initialize a deque (dq) to store the indices of elements in a increasing order of their values.
- Loop through the first (b-1) indices and maintain the deque such that it always contains indices of elements in increasing order of their prefix sum values.
- Loop through each starting index i from 0 to (n-a), for finding the maximum subarray sum starting at index (i+1).
- Inside the loop, adjust the deque to maintain the maximum value for the current window of size (b-a+1).
- If the current window's right end has a prefix sum greater than the front element in the deque, pop elements from the front until this condition is satisfied, and then push the right end index to the front.
- If the index of maximum element outside the current window , pop elements from the back of the deque until the back index is within the current window.
- Update the answer by taking the maximum of the current answer and the difference between the prefix sum at the back of the deque and the prefix sum at index I.
- After the loop, print the final answer, which represents the maximum sum of values in a contiguous subarray with length between a and b.
Below is the implementation of above approach:
C++ #include <bits/stdc++.h> using namespace std; typedef long long ll; void MaximumSubarraySumII(int N, int A, int B, vector<ll>& arr) { // Initialize a deque to store indices in increasing // order of prefix sum values deque<ll> dq; // Initialize a prefixSum array to store cumulative sums vector<ll> prefixSum(N + 1); // Initialize the answer to track the maximum sum ll ans = LLONG_MIN; // Calculate cumulative sums for (int i = 1; i <= N; i++) { prefixSum[i] += prefixSum[i - 1] + arr[i - 1]; } // Loop through the first (B-1) indices to initialize // deque for (int i = 1; i < B; i++) { // Maintain deque in increasing order of prefix sum // values while (!dq.empty() && prefixSum[dq.front()] <= prefixSum[i]) { dq.pop_front(); } dq.push_front(i); } // Loop through each starting index i from 0 to (n-a) for (int i = 0; i <= (N - A); i++) { // Maintain deque in increasing order of prefix sum // values while (i + B <= N && !dq.empty() && prefixSum[dq.front()] <= prefixSum[i + B]) { dq.pop_front(); } // Push the right end index to the front of deque if (i + B <= N) dq.push_front(i + B); // If the index of maximum element outside the // current window , pop elements from the back of // the deque until the back index(index of maximum // element) is within the current window. while (!dq.empty() && dq.back() < (A + i)) { dq.pop_back(); } // Update the answer by taking the maximum of the // current answer and the difference between the // prefix sum at the back(maximum element) of the // deque and the prefix sum at index i ans = max(ans, prefixSum[dq.back()] - prefixSum[i]); } // Print the final answer cout << ans << "\n"; } // Driver Code int main() { // Read input values n, a, b, and the array arr from the // standard input int N = 8, A = 1, B = 2; vector<ll> arr = { -1, 3, -2, 5, 3, -5, 2, 2 }; // Invoke the function MaximumSubarraySumII with the // provided inputs MaximumSubarraySumII(N, A, B, arr); }
Java import java.util.ArrayDeque; import java.util.Deque; public class MaximumSubarraySumII { static void maximumSubarraySumII(int N, int A, int B, long[] arr) { // Initialize a deque to store indices in increasing // order of prefix sum values Deque<Integer> dq = new ArrayDeque<>(); // Initialize a prefixSum array to store cumulative sums long[] prefixSum = new long[N + 1]; // Initialize the answer to track the maximum sum long ans = Long.MIN_VALUE; // Calculate cumulative sums for (int i = 1; i <= N; i++) { prefixSum[i] += prefixSum[i - 1] + arr[i - 1]; } // Loop through the first (B-1) indices to initialize deque for (int i = 1; i < B; i++) { // Maintain deque in increasing order of prefix sum values while (!dq.isEmpty() && prefixSum[dq.peekFirst()] <= prefixSum[i]) { dq.pollFirst(); } dq.addFirst(i); } // Loop through each starting index i from 0 to (N - A) for (int i = 0; i <= (N - A); i++) { // Maintain deque in increasing order of prefix sum values while (i + B <= N && !dq.isEmpty() && prefixSum[dq.peekFirst()] <= prefixSum[i + B]) { dq.pollFirst(); } // Push the right end index to the front of deque if (i + B <= N) dq.addFirst(i + B); // If the index of maximum element outside the // current window, pop elements from the back of // the deque until the back index (index of maximum // element) is within the current window. while (!dq.isEmpty() && dq.peekLast() < (A + i)) { dq.pollLast(); } // Update the answer by taking the maximum of the // current answer and the difference between the // prefix sum at the back (maximum element) of the // deque and the prefix sum at index i ans = Math.max(ans, prefixSum[dq.peekLast()] - prefixSum[i]); } // Print the final answer System.out.println(ans); } // Driver Code public static void main(String[] args) { // Read input values N, A, B, and the array arr from the standard input int N = 8, A = 1, B = 2; long[] arr = { -1, 3, -2, 5, 3, -5, 2, 2 }; // Invoke the function maximumSubarraySumII with the provided inputs maximumSubarraySumII(N, A, B, arr); } } // This code is contributed by rambabuguphka
C# using System; using System.Collections.Generic; public class Program { public static void MaximumSubarraySumII(int N, int A, int B, List<long> arr) { // Initialize a deque to store indices in increasing order of prefix sum values LinkedList<long> dq = new LinkedList<long>(); // Initialize a prefixSum array to store cumulative sums List<long> prefixSum = new List<long>(new long[N + 1]); // Initialize the answer to track the maximum sum long ans = long.MinValue; // Calculate cumulative sums for (int i = 1; i <= N; i++) { prefixSum[i] += prefixSum[i - 1] + arr[i - 1]; } // Loop through the first (B-1) indices to initialize deque for (int i = 1; i < B; i++) { // Maintain deque in increasing order of prefix sum values while (dq.Count > 0 && prefixSum[(int)dq.First.Value] <= prefixSum[i]) { dq.RemoveFirst(); } dq.AddFirst(i); } // Loop through each starting index i from 0 to (n-a) for (int i = 0; i <= (N - A); i++) { // Maintain deque in increasing order of prefix sum values while (i + B <= N && dq.Count > 0 && prefixSum[(int)dq.First.Value] <= prefixSum[i + B]) { dq.RemoveFirst(); } // Push the right end index to the front of deque if (i + B <= N) dq.AddFirst(i + B); // If the index of maximum element outside the current window, pop elements from the back of the deque until the back index(index of maximum element) is within the current window. while (dq.Count > 0 && dq.Last.Value < (A + i)) { dq.RemoveLast(); } // Update the answer by taking the maximum of the current answer and the difference between the prefix sum at the back(maximum element) of the deque and the prefix sum at index i ans = Math.Max(ans, prefixSum[(int)dq.Last.Value] - prefixSum[i]); } // Print the final answer Console.WriteLine(ans); } public static void Main() { // Read input values n, a, b, and the array arr from the standard input int N = 8, A = 1, B = 2; List<long> arr = new List<long> { -1, 3, -2, 5, 3, -5, 2, 2 }; // Invoke the function MaximumSubarraySumII with the provided inputs MaximumSubarraySumII(N, A, B, arr); } }
JavaScript function maximumSubarraySumII(N, A, B, arr) { // Initialize a deque to store indices in increasing // order of prefix sum values let dq = []; // Initialize a prefixSum array to store cumulative sums let prefixSum = new Array(N + 1).fill(0); // Initialize the answer to track the maximum sum let ans = Number.MIN_SAFE_INTEGER; // Calculate cumulative sums for (let i = 1; i <= N; i++) { prefixSum[i] += prefixSum[i - 1] + arr[i - 1]; } // Loop through the first (B-1) indices to initialize // deque for (let i = 1; i < B; i++) { // Maintain deque in increasing order of prefix sum // values while (dq.length !== 0 && prefixSum[dq[0]] <= prefixSum[i]) { dq.shift(); } dq.unshift(i); } // Loop through each starting index i from 0 to (n-a) for (let i = 0; i <= (N - A); i++) { // Maintain deque in increasing order of prefix sum // values while (i + B <= N && dq.length !== 0 && prefixSum[dq[0]] <= prefixSum[i + B]) { dq.shift(); } // Push the right end index to the front of deque if (i + B <= N) dq.unshift(i + B); // If the index of maximum element outside the // current window , pop elements from the back of // the deque until the back index(index of maximum // element) is within the current window. while (dq.length !== 0 && dq[dq.length - 1] < (A + i)) { dq.pop(); } // Update the answer by taking the maximum of the // current answer and the difference between the // prefix sum at the back(maximum element) of the // deque and the prefix sum at index i ans = Math.max(ans, prefixSum[dq[dq.length - 1]] - prefixSum[i]); } // Print the final answer console.log(ans); } // Driver Code // Read input values n, a, b, and the array arr from the // standard input let N = 8, A = 1, B = 2; let arr = [-1, 3, -2, 5, 3, -5, 2, 2]; // Invoke the function MaximumSubarraySumII with the // provided inputs maximumSubarraySumII(N, A, B, arr);
Python3 from collections import deque def MaximumSubarraySumII(N, A, B, arr): # Initialize a deque to store indices in increasing # order of prefix sum values dq = deque() # Initialize a prefixSum array to store cumulative sums prefix_sum = [0] * (N + 1) # Initialize the answer to track the maximum sum ans = float('-inf') # Calculate cumulative sums for i in range(1, N + 1): prefix_sum[i] = prefix_sum[i - 1] + arr[i - 1] # Loop through the first (B-1) indices to initialize # deque for i in range(1, B): # Maintain deque in increasing order of prefix sum # values while dq and prefix_sum[dq[0]] <= prefix_sum[i]: dq.popleft() dq.appendleft(i) # Loop through each starting index i from 0 to (n-a) for i in range(N - A + 1): # Maintain deque in increasing order of prefix sum # values while i + B <= N and dq and prefix_sum[dq[0]] <= prefix_sum[i + B]: dq.popleft() # Push the right end index to the front of deque if i + B <= N: dq.appendleft(i + B) # If the index of maximum element outside the # current window, pop elements from the back of # the deque until the back index(index of maximum # element) is within the current window. while dq and dq[-1] < A + i: dq.pop() # Update the answer by taking the maximum of the # current answer and the difference between the # prefix sum at the back(maximum element) of the # deque and the prefix sum at index i ans = max(ans, prefix_sum[dq[-1]] - prefix_sum[i]) # Print the final answer print(ans) # Driver Code if __name__ == "__main__": # Provided input values N = 8 A = 1 B = 2 arr = [-1, 3, -2, 5, 3, -5, 2, 2] # Invoke the function maximum_subarray_sum_ii with the # provided inputs MaximumSubarraySumII(N, A, B, arr)
Time Complexity: O(N), where N is the size of input array arr[].
Auxiliary Space: O(N)
Similar Reads
CSES Solutions - Maximum Subarray Sum Given an array arr[] of N integers, your task is to find the maximum sum of values in a contiguous, nonempty subarray. Examples: Input: N = 8, arr[] = {-1, 3, -2, 5, 3, -5, 2, 2}Output: 9Explanation: The subarray with maximum sum is {3, -2, 5, 3} with sum = 3 - 2 + 5 + 3 = 9. Input: N = 6, arr[] = {
5 min read
Maximum Subarray Sum in C++ In this article, we will learn how to find the maximum sum of a contiguous subarray within a given array of integers in C++ language. Finding the maximum subarray sum involves determining the contiguous subarray that has the largest sum.Example:Input:arr[] = {-2, 1, -3, 4, -1, 2, 1, -5, 4}Output:6Ex
7 min read
Maximum Product Subarray in C++ In this article, we will learn how to find the maximum product of a contiguous subarray within a given array of integers. This problem is a variation of the classic "Maximum Subarray Sum" problem and presents an additional challenge because it involves both positive and negative numbers in an array.
7 min read
Minimizing Maximum Absolute Subarray Sums Given an array arr[] of size N, we can choose any real number X which when subtracted from all the elements of the array then the maximum absolute subarray sum among all the subarrays is minimum. The task is to return the minimum of maximum absolute sum among all the subarrays. Note: The answer shou
12 min read
Maximum sum subarray of size range [L, R] Given an integer array arr[] of size N and two integer L and R. The task is to find the maximum sum subarray of size between L and R (both inclusive). Example: Input: arr[] = {1, 2, 2, 1}, L = 1, R = 3 Output: 5 Explanation: Subarray of size 1 are {1}, {2}, {2}, {1} and maximum sum subarray = 2 for
8 min read
POTD Solutions | 23 Octâ 23 | Maximum Sum Increasing Subsequence View all POTD Solutions Welcome to the daily solutions of our PROBLEM OF THE DAY (POTD). We will discuss the entire problem step-by-step and work towards developing an optimized solution. This will not only help you brush up on your concepts of Dynamic Programming but will also help you build up pro
4 min read