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
- 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.
- Sum Calculation:
- As we iterate through the array elements, we calculate the cumulative sum of the current portion of the array.
- 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.
- 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.
- 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:
-
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 bothpre_mx
ands
as 0 (to keep track of the maximum sum of a subarray found so far and the current sum of elements, respectively).
- We start by initializing several variables:
-
Iterating Through the Array:
- The algorithm iterates through each element of the array
nums
. For each elementx
at indexr
, it updates the current sums
by addingx
to it.
- The algorithm iterates through each element of the array
-
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 topre_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
tor
, effectively resetting the window to start from the current index. - Reset the
pre_mx
ands
to 0 to start recalculating the sum for the new window.
- Increment the
- When
-
Updating Maximum Sum:
- If
r - l >= 2
, even if no operation is required, we still updatepre_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.
- If
-
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.
- Once the loop is completed,
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 EvaluatorExample Walkthrough
Let's illustrate the solution approach using a small example. Consider the array nums = [4, -2, -3, 5, -1]
.
Step-by-step Solution:
-
Initialization:
- Set
l = -1
(end of last checked subarray),ans = 0
(to count operations), and bothpre_mx = 0
ands = 0
(to track the maximum previous subarray sum and the current sum, respectively).
- Set
-
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.
- Update
-
Index 1, x = -2:
- Update
s = s + x = 4 + (-2) = 2
. - Since
1 - (-1) <= 2
, we don't perform any checks or operations.
- Update
-
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
to1
. - Reset
l
to2
. - Reset
s = 0
andpre_mx = 0
.
- Increment
- Update
-
Index 3, x = 5:
- Update
s = s + x = 0 + 5 = 5
. - Since
3 - 2 <= 2
, no further action is required.
- Update
-
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 updatepre_mx
.
- Update
-
-
Result:
- The minimum number of operations required is
1
.
- The minimum number of operations required is
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.
The three-steps of Depth First Search are:
- Identify states;
- Draw the state-space tree;
- DFS on the state-space tree.
Recommended Readings
Greedy Introduction div class responsive iframe iframe src https www youtube com embed WTslqPbj7I title YouTube video player frameborder 0 allow accelerometer autoplay clipboard write encrypted media gyroscope picture in picture web share allowfullscreen iframe div When do we use greedy Greedy algorithms tend to solve optimization problems Typically they will ask you to calculate the max min of some value Commonly you may see this phrased in the problem as max min longest shortest largest smallest etc These keywords can be identified by just scanning
Prefix Sum The prefix sum is an incredibly powerful and straightforward technique Its primary goal is to allow for constant time range sum queries on an array What is Prefix Sum The prefix sum of an array at index i is the sum of all numbers from index 0 to i By
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Want a Structured Path to Master System Design Too? Don’t Miss This!