Maximum Sum of 3 Non-Overlapping Subarrays

Updated on 11 June, 2025
Maximum Sum of 3 Non-Overlapping Subarrays header image

Problem Statement

In this task, you are given an array nums of integers and an integer k. The objective is to identify three non-overlapping subarrays each of length k that together offer the maximum possible sum of their elements. The solution should return the positions (0-indexed) which mark the beginning of each of these three subarrays. If there exists more than one combination that fits the criteria for the maximum sum, you should return the set of indices that is lexicographically the smallest. This means that when selecting between two potential sets of indices, you pick the set where the earliest differing element is smaller.

Examples

Example 1

Input:

nums = [1,2,1,2,6,7,5,1], k = 2

Output:

[0,3,5]

Explanation:

Subarrays [1, 2], [2, 6], [7, 5] correspond to the starting indices [0, 3, 5].
We could have also taken [2, 1], but an answer of [1, 3, 5] would be lexicographically smaller.

Example 2

Input:

nums = [1,2,1,2,1,2,1,2,1], k = 2

Output:

[0,2,4]

Constraints

  • 1 <= nums.length <= 2 * 104
  • 1 <= nums[i] < 216
  • 1 <= k <= floor(nums.length / 3)

Approach and Intuition

  1. Given the constraints that the array length can be as great as 20,000 and we need three non-overlapping subarrays, a brute force approach is not feasible owing to its potential time complexity. Understanding the need for optimization is paramount.
  2. Resort to a dynamic programming strategy, possibly by using a suffix and prefix array to track the maximum sums starting from the beginning and the end of nums. This technique can efficiently capture the best subarrays of length k as we progress.
  3. For every possible central subarray (second of the three), calculate the best possible previously non-overlapping subarray to the left and the best possible non-overlaping subarray to the right. This provides a framework to consider not only local optimizations per subarray, but also the globally optimized solution.
  4. Maintain an array storing the best possible starts of a sequence of length k up to every index i, which allows for quick look-up of the best segment prior to starting a new one. This array will serve as a reference for constructing the optimal triple of start indices.
  5. We must consider the enforcement of the lexicographical order in cases where multiple indices offer the same sum. This can typically be managed by maintaining a structure that compares each candidate sequence as it is built.

It's crucial to balance between maintaining the global perspective of getting the largest sum for the three subarrays while adhering to the requirement of non-overlapping intervals and minimal lexicographical results — all within the constraints furnished by the problem's scope.

Solutions

  • C++
  • Java
  • Python
cpp
class Solution {
public:
    vector<int> findMaximumSumIndices(vector<int>& arr, int len) {
        int topSingle = 0;
        vector<int> topDouble = {0, len};
        vector<int> topTriple = {0, len, len * 2};

        int sumSingle = 0;
        for (int i = 0; i < len; i++) {
            sumSingle += arr[i];
        }

        int sumDouble = 0;
        for (int i = len; i < len * 2; i++) {
            sumDouble += arr[i];
        }

        int sumTriple = 0;
        for (int i = len * 2; i < len * 3; i++) {
            sumTriple += arr[i];
        }

        int maxSingle = sumSingle;
        int maxDouble = sumSingle + sumDouble;
        int maxTriple = sumSingle + sumDouble + sumTriple;

        int indexSingle = 1;
        int indexDouble = len + 1;
        int indexTriple = len * 2 + 1;

        while (indexTriple <= arr.size() - len) {
            sumSingle = sumSingle - arr[indexSingle - 1] + arr[indexSingle + len - 1];
            sumDouble = sumDouble - arr[indexDouble - 1] + arr[indexDouble + len - 1];
            sumTriple = sumTriple - arr[indexTriple - 1] + arr[indexTriple + len - 1];

            if (sumSingle > maxSingle) {
                topSingle = indexSingle;
                maxSingle = sumSingle;
            }

            if (sumDouble + maxSingle > maxDouble) {
                topDouble[0] = topSingle;
                topDouble[1] = indexDouble;
                maxDouble = sumDouble + maxSingle;
            }

            if (sumTriple + maxDouble > maxTriple) {
                topTriple[0] = topDouble[0];
                topTriple[1] = topDouble[1];
                topTriple[2] = indexTriple;
                maxTriple = sumTriple + maxDouble;
            }

            indexSingle++;
            indexDouble++;
            indexTriple++;
        }

        return topTriple;
    }
};

This code defines a C++ class Solution that aims to find indices for three non-overlapping subarrays from a provided array, so that the sum of these subarrays' elements is maximized. The length of each subarray is a specified integer len. The function findMaximumSumIndices takes a vector arr and an integer len, and returns the starting indices of the three optimal subarrays as a vector of integers.

Key Processes Explained:

  • Initialization:

    • The vectors topSingle, topDouble, and topTriple hold the current best indices for one, two, and three subarrays respectively. Initially, these are set to start at 0, len, and 2 * len.
    • sumSingle, sumDouble, and sumTriple hold the sums of elements contained in the subarrays starting from these initial indices.
    • maxSingle, maxDouble, and maxTriple are the maximum sums found so far for combinations of one, two, or three subarrays.
  • Sum Calculation:

    • The sums for the three initial subarrays are calculated in a straightforward manner by iterating over the specified number of elements directly following each starting index.
  • Iteration and Recalculation:

    • The function then enters a loop that iterates from the initial indices up to possible valid positions within the bounds of the array size minus len (to ensure subarray length can be maintained).
    • For each increment step, the oldest element in each subarray sum is removed and the next consecutive element in the array is added, updating the sums to reflect the new subarrays formed by these sliding windows.
  • Updating Maximums and Indices:

    • Conditions check if the newly computed sum for any configuration (single, double combined with the best single, or triple combined with the best double) exceeds the previously recorded maximum. If any condition is met, the indices and maximum sums are updated accordingly to reflect this better configuration.

At the end of the function, topTriple containing the indices yielding the highest sum of the three subarrays is returned. This solution is efficient as it works through the array in linear progression, updating potential best indices based on dynamically computed subarray sums.

java
class Solution {

    public int[] maxSumOfThreeSubarrays(int[] data, int k) {
        // Variables to track the best indices for one, two, and three subarray configurations
        int topSingleStart = 0;
        int[] topDoubleStart = { 0, k };
        int[] topTripleStart = { 0, k, 2 * k };

        // Compute the initial sums for the first three subarrays
        int singleWindowSum = 0;
        for (int i = 0; i < k; i++) {
            singleWindowSum += data[i];
        }

        int doubleWindowSum = 0;
        for (int i = k; i < 2 * k; i++) {
            doubleWindowSum += data[i];
        }

        int tripleWindowSum = 0;
        for (int i = 2 * k; i < 3 * k; i++) {
            tripleWindowSum += data[i];
        }

        // Track the best sums encountered so far
        int maxSingleSum = singleWindowSum;
        int maxDoubleSum = singleWindowSum + doubleWindowSum;
        int maxTripleSum =
            singleWindowSum +
            doubleWindowSum +
            tripleWindowSum;

        // Sliding window pointers for the subarrays
        int singleIndex = 1;
        int doubleIndex = k + 1;
        int tripleIndex = 2 * k + 1;

        // Slide the windows across the array
        while (tripleIndex <= data.length - k) {
            // Update the sums using the sliding window technique
            singleWindowSum =
                singleWindowSum -
                data[singleIndex - 1] +
                data[singleIndex + k - 1];
            doubleWindowSum =
                doubleWindowSum -
                data[doubleIndex - 1] +
                data[doubleIndex + k - 1];
            tripleWindowSum =
                tripleWindowSum -
                data[tripleIndex - 1] +
                data[tripleIndex + k - 1];

            // Update the best single subarray start index if a better sum is found
            if (singleWindowSum > maxSingleSum) {
                topSingleStart = singleIndex;
                maxSingleSum = singleWindowSum;
            }

            // Update the best double subarray start indices if a better sum is found
            if (doubleWindowSum + maxSingleSum > maxDoubleSum) {
                topDoubleStart[0] = topSingleStart;
                topDoubleStart[1] = doubleIndex;
                maxDoubleSum = doubleWindowSum + maxSingleSum;
            }

            // Update the best triple subarray start indices if a better sum is found
            if (tripleWindowSum + maxDoubleSum > maxTripleSum) {
                topTripleStart[0] = topDoubleStart[0];
                topTripleStart[1] = topDoubleStart[1];
                topTripleStart[2] = tripleIndex;
                maxTripleSum = tripleWindowSum + maxDoubleSum;
            }

            // Move the sliding windows forward
            singleIndex += 1;
            doubleIndex += 1;
            tripleIndex += 1;
        }

        // Return the starting indices of the three subarrays with the maximum sum
        return topTripleStart;
    }
}

The given Java solution addresses the problem of finding the maximum sum of three non-overlapping subarrays of a specified length k from a given array. The function maxSumOfThreeSubarrays approaches this by utilizing a sliding window technique to efficiently calculate the sums of possible subarrays and then updates the best potential positions for these subarrays as it iterates through the main data array.

The approach includes:

  • Initializing sums for the first possible set of three subarrays using loop-based sum calculations.
  • Setting up initial "best" starting indices for the subarrays that will be adjusted as greater sums are found.
  • Using a while loop to slide through possible positions of the array efficiently, adjusting the window sums by subtracting a value exiting the window and adding a new value entering the window.
  • Continuously comparing and updating the stored maximum sums and associated starting indices if a higher sum is found either for single subarrays or combinations of two and three subarrays.
  • The algorithm completes when it has exhausted possible positions for the third subarray (the last window).
  • The result, an array containing the starting indices of the three highest sum subarrays, is then returned.

This implementation is optimal in terms of both time and space complexity, ensuring performance and efficiency by effectively minimizing the redundant calculations. The use of a systematic window sliding technique helps in maintaining constant checks on the sums, allowing for consistent updates of the maximum sums found and their respective positions. This systematic strategy allows the solution to adapt dynamically to the contents of the data array while ensuring all conditions of non-overlap and specified subarray length are met.

python
class Solution:
    def findMaxSumSubarrays(self, arr: List[int], window_size: int) -> List[int]:
        # Initialize the starting positions for subarrays
        top_single = 0
        top_double = [0, window_size]
        top_trio = [0, window_size, window_size * 2]

        # Initial sums for each section
        sum_single = sum(arr[:window_size])
        sum_double = sum(arr[window_size : window_size * 2])
        sum_trio = sum(arr[window_size * 2 : window_size * 3])

        # Maximum sums found
        max_single = sum_single
        max_double = sum_single + sum_double
        max_trio = sum_single + sum_double + sum_trio

        # Starting indices for sliding windows
        index_single = 1
        index_double = window_size + 1
        index_trio = window_size * 2 + 1

        # Iterate over the array using a sliding window approach
        while index_trio <= len(arr) - window_size:
            # Update the sums by sliding the window
            sum_single = (
                sum_single
                - arr[index_single - 1]
                + arr[index_single + window_size - 1]
            )
            sum_double = (
                sum_double
                - arr[index_double - 1]
                + arr[index_double + window_size - 1]
            )
            sum_trio = (
                sum_trio
                - arr[index_trio - 1]
                + arr[index_trio + window_size - 1]
            )

            # Update the best single interval
            if sum_single > max_single:
                top_single = index_single
                max_single = sum_single

            # Check and update for better two-interval sums
            if sum_double + max_single > max_double:
                top_double[0] = top_single
                top_double[1] = index_double
                max_double = sum_double + max_single

            # Check and update for the best three-interval sums
            if sum_trio + max_double > max_trio:
                top_trio[0] = top_double[0]
                top_trio[1] = top_double[1]
                top_trio[2] = index_trio
                max_trio = sum_trio + max_double

            # Increment the starting indices for the next window shift
            index_single += 1
            index_double += 1
            index_trio += 1

        # Return the positions for the optimal sum arrangement
        return top_trio

Maximize the sum of three non-overlapping subarrays using a Python solution that employs a sliding window technique. This approach optimizes the computational efficiency, ideal for handling large datasets. The function findMaxSumSubarrays takes an integer array and a window size as inputs. Here's a breakdown of the process:

  1. Initialize variables to store the starting indices of the best subarrays, their sums, and the maximum sums found as you move through the array.
  2. Using a sliding window, update the sums of three different windows every time the window moves to right.
  3. Ensure constant updates on maximum sums found for single, double, and trio windows.
  4. For every window move:
    • Update sum by removing the element that's left out of the window and adding the new element coming into the window from right.
    • Check and update the top indices if a new maximum for single, double (combination of best single subarray and current double window) or trio (combination of best double subarray and current triple window) is found.
  5. The loop continues until the end of the array is reached.
  6. The function returns the indices of the optimal three subarrays.

The method efficiently keeps track of the best subarray combinations while conducting overlap checks, through continuous updating of sums during the window shift for an effective solution.

Comments

No comments yet.