Facebook Pixel

3511. Make a Positive Array 🔒

Problem Description

You are given an array nums. An array is considered positive if the sum of all numbers in each subarray that has more than two elements is positive.

You can perform the following operation any number of times:

  • Replace one element in nums with any integer between -1018 and 1018.

The goal is to find the minimum number of operations needed to make nums positive.

Intuition

The task is to ensure that every subarray with more than two elements has a positive sum. This means for any subarray of length greater than two, its cumulative sum must be greater than zero.

Solution Approach

  1. Sliding Window Technique:
    • The problem can be approached using a sliding window technique where we try to maintain a window of a length greater than two.
  2. Sum Calculation:
    • As we iterate through the array elements, we calculate the cumulative sum of the current portion of the array.
  3. Comparison and Adjustment:
    • If at any point the cumulative sum becomes non-positive for a subarray longer than two elements, it signals that changes are needed to make the sum positive.
    • The algorithm checks if removing some elements from this subarray helps achieve a positive sum.
  4. Maintaining Preceding Maximum Sum:
    • To efficiently determine when to perform a replacement, keep track of the maximum sum of a subarray ending before the current element.
    • If the current cumulative sum with more than two elements falls below this maximum, a replacement operation is performed.
  5. Counting Operations:
    • The number of such replacements needed is counted and returned as the result.

By leveraging these strategies, the algorithm efficiently determines the minimum number of replacements required to ensure all subarrays with more than two elements have positive sums.

Learn more about Greedy and Prefix Sum patterns.

Solution Approach

The solution for making an array nums positive involves using a combination of algorithms, specifically the sliding window technique and maintaining a running total to determine when and where to replace elements.

Here’s a breakdown of how the solution works:

  1. Initialization:

    • We start by initializing several variables: l as -1 (to act as a pointer for the end of the last checked subarray), ans as 0 (to count the number of operations), and both pre_mx and s as 0 (to keep track of the maximum sum of a subarray found so far and the current sum of elements, respectively).
  2. Iterating Through the Array:

    • The algorithm iterates through each element of the array nums. For each element x at index r, it updates the current sum s by adding x to it.
  3. Check Subarray Conditions:

    • When r - l > 2, it indicates that we have more than two elements in the current window (or subarray).
    • At this point, the algorithm checks whether the current sum s is less than or equal to pre_mx. If it is, this means the subarray sum is not positive, and we must perform an operation:
      • Increment the ans counter as a replacement operation is required.
      • Update l to r, effectively resetting the window to start from the current index.
      • Reset the pre_mx and s to 0 to start recalculating the sum for the new window.
  4. Updating Maximum Sum:

    • If r - l >= 2, even if no operation is required, we still update pre_mx with the maximum between its current value and the sum excluding the most recent two elements (s - x - nums[r - 1]). This ensures we have the highest possible sum for a valid previous subarray to compare against the current one.
  5. Returning the Result:

    • Once the loop is completed, ans holds the minimum number of replacement operations needed to make the array such that every subarray with more than two elements is positive.

This approach efficiently handles the problem by leveraging a sliding window to maintain relevant sums and perform necessary adjustments, ensuring that operations are minimal and the array requirements are met.

Ready to land your dream job?

Unlock your dream job with a 2-minute evaluator for a personalized learning plan!

Start Evaluator

Example Walkthrough

Let's illustrate the solution approach using a small example. Consider the array nums = [4, -2, -3, 5, -1].

Step-by-step Solution:

  1. Initialization:

    • Set l = -1 (end of last checked subarray), ans = 0 (to count operations), and both pre_mx = 0 and s = 0 (to track the maximum previous subarray sum and the current sum, respectively).
  2. Iterating Through the Array:

    • Index 0, x = 4:

      • Update s = s + x = 0 + 4 = 4.
      • Since 0 - (-1) <= 2, we don't perform any checks or operations.
    • Index 1, x = -2:

      • Update s = s + x = 4 + (-2) = 2.
      • Since 1 - (-1) <= 2, we don't perform any checks or operations.
    • Index 2, x = -3:

      • Update s = s + x = 2 + (-3) = -1.
      • Now, 2 - (-1) > 2 which means our subarray has more than two elements (subarray: [4, -2, -3]).
      • Since s <= pre_mx (-1 <= 0), perform an operation:
        • Increment ans to 1.
        • Reset l to 2.
        • Reset s = 0 and pre_mx = 0.
    • Index 3, x = 5:

      • Update s = s + x = 0 + 5 = 5.
      • Since 3 - 2 <= 2, no further action is required.
    • Index 4, x = -1:

      • Update s = s + x = 5 + (-1) = 4.
      • Now, 4 - 2 > 2, so our current window: [5, -1] has more than two elements.
      • Since s > pre_mx (4 > 0), no operation needed but update pre_mx.
  3. Result:

    • The minimum number of operations required is 1.

In this example, the process ensures any necessary replacements are made to maintain positive sums in all pertinent subarrays.

Solution Implementation

1from typing import List
2
3class Solution:
4    def makeArrayPositive(self, nums: List[int]) -> int:
5        # Initialize pointers and variables
6        l = -1  # left boundary of the current subarray
7        ans = 0  # count of operations needed
8        pre_mx = 0  # previous maximum sum without considering the last element
9        s = 0  # current sum of the subarray
10
11        # Iterate over the elements in nums with index
12        for r, x in enumerate(nums):
13            s += x  # Add the current element to the sum
14
15            # Check if the subarray length exceeds 2 and the sum is less than or equal to pre_mx
16            if r - l > 2 and s <= pre_mx:
17                ans += 1  # Increment the number of operations
18                l = r  # Update the left boundary
19                pre_mx = s = 0  # Reset pre_mx and the sum
20
21            # When subarray length is at least 2, update pre_mx to max of itself and the sum excluding last two elements
22            elif r - l >= 2:
23                pre_mx = max(pre_mx, s - x - nums[r - 1])
24
25        return ans  # Return the total number of operations needed
26
1class Solution {
2    public int makeArrayPositive(int[] nums) {
3        // Initialize the answer count to zero
4        int ans = 0;
5        // Pre-max and running sum initialized to zero
6        long preMax = 0, sum = 0;
7
8        // Iterate through the array with two pointers: l (left) and r (right)
9        for (int left = -1, right = 0; right < nums.length; right++) {
10            int currentNum = nums[right];
11            sum += currentNum;
12          
13            // Check if the current subarray (from left to right) can be split
14            if (right - left > 2 && sum <= preMax) {
15                ans++;             // Increment the count of splits
16                left = right;      // Move the left pointer to the current position
17                preMax = sum = 0;  // Reset preMax and sum
18            } else if (right - left >= 2) {
19                // Update preMax to the maximum of its current value or the sum excluding the last two elements
20                preMax = Math.max(preMax, sum - currentNum - nums[right - 1]);
21            }
22        }
23      
24        // Return the number of necessary operations
25        return ans;
26    }
27}
28
1#include <vector>
2#include <algorithm> // for max
3
4class Solution {
5public:
6    int makeArrayPositive(std::vector<int>& nums) {
7        int operationsCount = 0;
8        long long maxPrefixSum = 0, currentSum = 0;
9      
10        // l is the left pointer of the window, r is the right pointer
11        for (int left = -1, right = 0; right < nums.size(); right++) {
12            int currentNum = nums[right];
13            currentSum += currentNum; // Add current number to the running sum
14
15            // Check if the window size exceeds 2 and the current sum is not greater than maxPrefixSum
16            if (right - left > 2 && currentSum <= maxPrefixSum) {
17                operationsCount++; // Increment the number of operations needed
18                left = right; // Move the left pointer to the current position of right
19                // Reset maxPrefixSum and currentSum for the new subarray
20                maxPrefixSum = currentSum = 0;
21            } else if (right - left >= 2) {
22                // Update maxPrefixSum considering current subarray calculation
23                maxPrefixSum = std::max(maxPrefixSum, currentSum - currentNum - nums[right - 1]);
24            }
25        }
26      
27        return operationsCount; // Return the total number of operations needed
28    }
29};
30
1// Function to calculate how many operations are needed to make any given array positive
2function makeArrayPositive(nums: number[]): number {
3    let left = -1; // Initialize the left index to track the start of the subarray
4    let [operations, previousMax, sum] = [0, 0, 0]; // Initialize counters and sum
5
6    // Iterate over each number in the nums array using the right index
7    for (let right = 0; right < nums.length; right++) {
8        const currentNum = nums[right]; // Current number from the array
9        sum += currentNum; // Add the current number to the sum
10
11        // Check if the current subarray is longer than 2 and if the sum is less than or equal to previousMax
12        if (right - left > 2 && sum <= previousMax) {
13            operations++; // Increment the operations counter
14            left = right; // Move the left index to right
15            previousMax = 0; // Reset previousMax
16            sum = 0; // Reset sum
17        } else if (right - left >= 2) { 
18            // If subarray is at least length 2
19            previousMax = Math.max(previousMax, sum - currentNum - nums[right - 1]);
20        }
21    }
22
23    return operations; // Return the total number of operations needed
24}
25

Time and Space Complexity

The time complexity of the provided code is O(n), where n is the length of the input list nums. This is because the code iterates over the list once with a for loop, performing constant-time operations at each step.

The space complexity of the code is O(1). The code uses a fixed amount of extra space, regardless of the size of the input list, for variables like l, ans, pre_mx, and s.

Learn more about how to find time and space complexity quickly.


Discover Your Strengths and Weaknesses: Take Our 2-Minute Quiz to Tailor Your Study Plan:

The three-steps of Depth First Search are:

  1. Identify states;
  2. Draw the state-space tree;
  3. DFS on the state-space tree.

Recommended Readings

Want a Structured Path to Master System Design Too? Don’t Miss This!

Load More