将数组划分成若干好子数组的方式
难度:
标签:
题目描述
You are given a binary array nums
.
A subarray of an array is good if it contains exactly one element with the value 1
.
Return an integer denoting the number of ways to split the array nums
into good subarrays. As the number may be too large, return it modulo 109 + 7
.
A subarray is a contiguous non-empty sequence of elements within an array.
Example 1:
Input: nums = [0,1,0,0,1] Output: 3 Explanation: There are 3 ways to split nums into good subarrays: - [0,1] [0,0,1] - [0,1,0] [0,1] - [0,1,0,0] [1]
Example 2:
Input: nums = [0,1,0] Output: 1 Explanation: There is 1 way to split nums into good subarrays: - [0,1,0]
Constraints:
1 <= nums.length <= 105
0 <= nums[i] <= 1
代码结果
运行时间: 144 ms, 内存: 19.7 MB
/*
* 给定一个二元数组 nums。
* 如果某个子数组恰好只存在一个值为 1 的元素,则认为该子数组是一个好子数组。
* 要统计将数组 nums 划分成若干好子数组的方法数,并返回其对 10^9 + 7 取余之后的结果。
*
* 思路:
* 1. 使用 Java Stream 记录所有 1 的位置。
* 2. 计算每两个相邻 1 之间的距离,然后可以选择插入这些位置的好子数组数目。
* 3. 最后将所有的可能性相乘,即为结果。
*/
import java.util.*;
import java.util.stream.*;
public class GoodSubarraysStream {
public int numGoodSubarrays(int[] nums) {
final int MOD = 1000000007;
List<Integer> onesPositions = IntStream.range(0, nums.length)
.filter(i -> nums[i] == 1)
.boxed()
.collect(Collectors.toList());
if (onesPositions.size() == 0) return 0;
long result = IntStream.range(1, onesPositions.size())
.mapToLong(i -> onesPositions.get(i) - onesPositions.get(i - 1))
.reduce(1, (a, b) -> (a * b) % MOD);
return (int) result;
}
public static void main(String[] args) {
GoodSubarraysStream gs = new GoodSubarraysStream();
int[] nums1 = {0, 1, 0, 0, 1};
System.out.println(gs.numGoodSubarrays(nums1)); // 输出: 3
int[] nums2 = {0, 1, 0};
System.out.println(gs.numGoodSubarrays(nums2)); // 输出: 1
}
}
解释
方法:
此题解的核心思想是使用动态规划的思路来统计好子数组的分割方法。首先,定义两个变量pre用于记录上一个数字1的位置(初始化为-1),res用于统计分割方法的总数(初始化为1)。遍历数组,每当遇到数字1时,若之前已遇到过数字1(即pre不为-1),则计算当前1的位置与上一个1的位置之间的元素个数,并用这个距离乘以之前的统计结果更新res,这样做是因为新的1可以与之前的所有好子数组组合形成新的好子数组。最后,如果整个数组中至少有一个1,返回res,否则返回0(没有好子数组的情况)。
时间复杂度:
O(n)
空间复杂度:
O(1)
代码细节讲解
🦆
在动态规划的解法中,为什么选择将上一个1的位置和当前1的位置之间的距离作为乘法因子来更新结果?
▷🦆
题解中提到如果整个数组中没有1,则返回0。这种情况是否意味着没有任何好子数组可以形成,即使数组中全部是0?
▷🦆
如何理解题解中提到的`res = (res * (idx-pre)) % 1_000_000_007`这一行代码?具体来说,这里的`(idx-pre)`代表什么,为什么需要这样更新res?
▷🦆
在题解的实现中,`pre`变量初始化为-1,这种初始化方式有什么特殊的意义或好处?
▷