3354. Make Array Elements Equal to Zero
Problem Description
You are given an integer array nums
. The task is to start by selecting a starting position curr
such that nums[curr] == 0
, and then choose a movement direction, either left or right. Following that, repeat the following process:
- If
curr
is out of the range[0, n - 1]
, the process ends. - If
nums[curr] == 0
, move in the current direction by incrementingcurr
if moving right, or decrementingcurr
if moving left. - If
nums[curr] > 0
:- Decrease
nums[curr]
by 1. - Reverse your movement direction (left becomes right and vice versa).
- Take a step in your new direction.
- Decrease
A selection of the initial position curr
and movement direction is considered valid if every element in nums
becomes 0 by the end of the process. The goal is to return the number of possible valid selections.
Intuition
The problem involves navigating through an array with certain initial choices, and the goal is to identify configurations that will result in the array becoming all zeros. The key insight is to think in terms of balance. We can align this "balance" concept by looking at prefix sums:
- Calculate a total sum
s
of the array. - For each zero-value element in the array, calculate the sum of all the elements to its left (
l
). The elements to the right will sum tos - l
. - Check two scenarios:
- If the sum of the left and right are equal (
l = s - l
), moving from the zero in either direction will eventually balance the whole array to zero. Such a case can be approached from both directions, hence contributes 2 valid solutions. - If the absolute difference between the two sums (
|l - (s - l)|
) is 1, start from the zero and choose the direction towards thelarger
side to balance the entire array to zeros. This scenario provides 1 valid solution.
- If the sum of the left and right are equal (
This logic is implemented efficiently with a single pass through the array and uses the prefix calculation.
Learn more about Prefix Sum patterns.
Solution Approach
The solution leverages the concept of prefix sums to keep track of the potential valid starting points and directions. Here's how it works:
-
Summation: First, compute the total sum
s
of all elements in the arraynums
. -
Initialization: Initialize two variables:
ans
(to store the number of valid selections) andl
(to keep a running prefix sum of elements encountered thus far). -
Iteration: Iterate through each element
x
innums
:- If
x
is not zero, accumulate it intol
. - If
x
is zero:- Check if
2 * l == s
. This condition implies the sum of elements on both sides of the current zero are equal, hence the array can be balanced by starting movement either left or right from this point. Increaseans
by 2 for these two possible directions. - Otherwise, if
|2 * l - s| == 1
, it indicates that the absolute difference between the left and right sums is 1. Depending on which side is larger, the direction from this zero value can be selected. Increaseans
by 1, as there's only one valid direction.
- Check if
- If
-
Return Result: Finally, return
ans
as the count of valid selections.
Using this approach, the problem is solved efficiently with a single pass through the array, making it a linear time complexity solution.
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 consider the array nums = [1, 0, 2, 1, 0, 2, 3, 0]
to illustrate the solution approach.
Step 1: Summation
Compute the total sum s
of the array:
[ s = 1 + 0 + 2 + 1 + 0 + 2 + 3 + 0 = 9 ]
Step 2: Initialization
Initialize ans = 0
to store the number of valid selections, and l = 0
for the running prefix sum.
Step 3: Iteration
Iterate through each element:
-
Index 0 (
x = 1
):
Addx
tol
:
[ l = l + 1 = 1 ] -
Index 1 (
x = 0
):
Check conditions:- ( 2 \times l = 2 \times 1 = 2 \neq 9 )
- (|2 \times l - s| = |2 - 9| = 7 \neq 1)
No valid starting positions from this zero.
-
Index 2 (
x = 2
):
Addx
tol
:
[ l = l + 2 = 3 ] -
Index 3 (
x = 1
):
Addx
tol
:
[ l = l + 1 = 4 ] -
Index 4 (
x = 0
):
Check conditions:- ( 2 \times l = 2 \times 4 = 8 \neq 9 )
- (|2 \times l - s| = |8 - 9| = 1)
The absolute difference is 1, thus a selection starting from here can balance the array.
Incrementans
by 1:
[ ans = 1 ]
-
Index 5 (
x = 2
):
Addx
tol
:
[ l = l + 2 = 6 ] -
Index 6 (
x = 3
):
Addx
tol
:
[ l = l + 3 = 9 ] -
Index 7 (
x = 0
):
Check conditions:- ( 2 \times l = 2 \times 9 = 18 \neq 9 )
- (|2 \times l - s| = |18 - 9| = 9 \neq 1)
No valid selections from this zero.
Step 4: Return Result
The count of valid selections is ( \text{ans} = 1 ).
Thus, using the solution approach, we find that there is 1 valid way to select a starting position and direction so that all elements in nums
would eventually become zero.
Solution Implementation
1from typing import List
2
3class Solution:
4 def countValidSelections(self, nums: List[int]) -> int:
5 # Calculate the total sum of the list
6 total_sum = sum(nums)
7 # Initialize answer and cumulative left sum to zero
8 ans = left_sum = 0
9
10 # Iterate through each element in the list
11 for num in nums:
12 if num != 0:
13 # Add to left_sum if the element is non-zero
14 left_sum += num
15 else:
16 # Check if double the left_sum is equal to total_sum
17 if left_sum * 2 == total_sum:
18 ans += 2
19 # Check if the absolute difference between double the left_sum and total_sum is 1
20 elif abs(left_sum * 2 - total_sum) == 1:
21 ans += 1
22 return ans
23
1import java.util.Arrays;
2
3class Solution {
4
5 // Method to count valid selections in the array
6 public int countValidSelections(int[] nums) {
7 // Calculate the sum of all elements in the array
8 int totalSum = Arrays.stream(nums).sum();
9
10 int validSelectionsCount = 0;
11 int currentSum = 0;
12
13 // Iterate through each element in the array
14 for (int num : nums) {
15 // If the element is non-zero, add it to the current sum
16 if (num != 0) {
17 currentSum += num;
18 } else {
19 // Check if the current sum is half of the total sum
20 // If true, increment the count by 2
21 if (currentSum * 2 == totalSum) {
22 validSelectionsCount += 2;
23 }
24 // Check if the absolute difference between
25 // double the current sum and the total sum is 1
26 // If true, increment the count by 1
27 else if (Math.abs(currentSum * 2 - totalSum) <= 1) {
28 validSelectionsCount++;
29 }
30 }
31 }
32
33 return validSelectionsCount;
34 }
35}
36
1#include <vector>
2#include <numeric> // For std::accumulate
3#include <cmath> // For std::abs
4
5class Solution {
6public:
7 int countValidSelections(std::vector<int>& nums) {
8 // Calculate the sum of all elements in nums
9 int total_sum = std::accumulate(nums.begin(), nums.end(), 0);
10
11 int valid_selections = 0; // Initialize the counter for valid selections
12 int partial_sum = 0; // Initialize partial sum for the subarray
13
14 // Iterate through each element in the nums vector
15 for (int x : nums) {
16 if (x != 0) {
17 // If the current element is non-zero, add it to the partial sum
18 partial_sum += x;
19 } else {
20 // If the current element is zero, check the conditions
21 if (partial_sum * 2 == total_sum) {
22 // If twice the partial sum equals the total sum, add 2 to valid selections
23 valid_selections += 2;
24 } else if (std::abs(partial_sum * 2 - total_sum) <= 1) {
25 // If the absolute difference between twice the partial sum and the total sum is at most 1, add 1 to valid selections
26 ++valid_selections;
27 }
28 }
29 }
30
31 return valid_selections; // Return the count of valid selections
32 }
33};
34
1function countValidSelections(nums: number[]): number {
2 // Calculate the sum of all elements in the array `nums`
3 const totalSum = nums.reduce((accumulator, currentValue) => accumulator + currentValue, 0);
4
5 // Initialize answer and left sum as zero
6 let answer = 0;
7 let leftSum = 0;
8
9 // Iterate through each number in the array
10 for (const num of nums) {
11 if (num) {
12 // Increment the left sum when the current number is non-zero
13 leftSum += num;
14 } else {
15 // Check if the current left sum multiplied by 2 equals the total sum
16 if (leftSum * 2 === totalSum) {
17 // Increment answer by 2 if condition is met
18 answer += 2;
19 } else if (Math.abs(leftSum * 2 - totalSum) <= 1) {
20 // Increment answer by 1 if the difference is at most 1
21 ++answer;
22 }
23 }
24 }
25
26 // Return the final computed answer
27 return answer;
28}
29
Time and Space Complexity
The time complexity of the code is O(n)
, where n
is the length of the array nums
. This is because each element in the array is processed exactly once in a single pass through the array.
The space complexity of the code is O(1)
, as no additional data structures that grow with the input size n
are used. The variables s
, ans
, and l
consume constant space.
Learn more about how to find time and space complexity quickly.
Which algorithm is best for finding the shortest distance between two points in an unweighted graph?
Recommended Readings
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
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https algomonster s3 us east 2 amazonaws com recursion jpg You first
Want a Structured Path to Master System Design Too? Don’t Miss This!