Given an integer array nums
, return the number of subarrays filled with 0
.
A subarray is a contiguous non-empty sequence of elements within an array.
Example 1:
Input: nums = [1,3,0,0,2,0,0,4] Output: 6 Explanation: There are 4 occurrences of [0] as a subarray. There are 2 occurrences of [0,0] as a subarray. There is no occurrence of a subarray with a size more than 2 filled with 0. Therefore, we return 6.
Example 2:
Input: nums = [0,0,0,2,0,0] Output: 9 Explanation: There are 5 occurrences of [0] as a subarray. There are 3 occurrences of [0,0] as a subarray. There is 1 occurrence of [0,0,0] as a subarray. There is no occurrence of a subarray with a size more than 3 filled with 0. Therefore, we return 9.
Example 3:
Input: nums = [2,10,2019] Output: 0 Explanation: There is no subarray filled with 0. Therefore, we return 0.
Constraints:
1 <= nums.length <= 105
-109 <= nums[i] <= 109
The problem asks to find the number of subarrays filled with only zeros in a given integer array. A naive approach would involve iterating through all possible subarrays and checking if they contain only zeros. However, this would lead to a time complexity of O(n^2), where n is the length of the input array. A much more efficient solution exists.
Efficient Approach
The key observation is that we don't need to explicitly check every subarray. Instead, we can iterate through the array once and keep track of the current consecutive sequence of zeros.
Initialization: We start with a counter cnt
initialized to 0 and a variable ans
to store the total count of zero-filled subarrays, also initialized to 0.
Iteration: We iterate through the input array nums
.
Zero Encountered: If we encounter a zero (v == 0
), we increment cnt
. This cnt
represents the length of the current consecutive zero sequence. The number of zero-filled subarrays ending at this position is equal to cnt
. We add cnt
to ans
.
Non-zero Encountered: If we encounter a non-zero number (v != 0
), we reset cnt
to 0 because the consecutive zero sequence is broken.
Final Result: After iterating through the entire array, ans
will hold the total number of zero-filled subarrays.
Time and Space Complexity Analysis
Time Complexity: O(n), where n is the length of the input array. We iterate through the array only once.
Space Complexity: O(1). We use only a few constant extra variables (ans
and cnt
).
Code Explanation (Python)
The Python code efficiently implements this approach:
class Solution:
def zeroFilledSubarray(self, nums: List[int]) -> int:
ans = cnt = 0
for v in nums:
cnt = 0 if v else cnt + 1
ans += cnt
return ans
The if v else cnt + 1
part is a concise way to express the conditional logic: if v
is 0, increment cnt
; otherwise, set cnt
to 0. The rest of the code directly implements the steps outlined above.
Code in other languages:
The code examples provided in Java, C++, Go, and TypeScript follow the same algorithm and have the same time and space complexity. They differ only in syntax and data type handling specific to each language. The core logic remains consistent across all implementations.
For instance, the Java code is:
class Solution {
public long zeroFilledSubarray(int[] nums) {
long ans = 0;
int cnt = 0;
for (int v : nums) {
cnt = v != 0 ? 0 : cnt + 1;
ans += cnt;
}
return ans;
}
}
The C++ code is:
class Solution {
public:
long long zeroFilledSubarray(vector<int>& nums) {
long long ans = 0;
int cnt = 0;
for (int& v : nums) {
cnt = v ? 0 : cnt + 1;
ans += cnt;
}
return ans;
}
};
The Go code is:
func zeroFilledSubarray(nums []int) (ans int64) {
cnt := 0
for _, v := range nums {
if v != 0 {
cnt = 0
} else {
cnt++
}
ans += int64(cnt)
}
return
}
And the TypeScript code is:
function zeroFilledSubarray(nums: number[]): number {
let ans = 0;
let cnt = 0;
for (const v of nums) {
cnt = v ? 0 : cnt + 1;
ans += cnt;
}
return ans;
}
All these variations maintain the linear time complexity and constant space complexity of the algorithm.