给你一个下标从 0 开始且长度为 n 的整数数组 differences ,它表示一个长度为 n + 1 的 隐藏 数组 相邻 元素之间的 差值 。更正式的表述为:我们将隐藏数组记作 hidden ,那么 differences[i] = hidden[i + 1] - hidden[i] 。
同时给你两个整数 lower 和 upper ,它们表示隐藏数组中所有数字的值都在 闭 区间 [lower, upper] 之间。
- 比方说,
differences = [1, -3, 4] ,lower = 1 ,upper = 6 ,那么隐藏数组是一个长度为4 且所有值都在 1 和 6 (包含两者)之间的数组。
[3, 4, 1, 5] 和 [4, 5, 2, 6] 都是符合要求的隐藏数组。
[5, 6, 3, 7] 不符合要求,因为它包含大于 6 的元素。
[1, 2, 3, 4] 不符合要求,因为相邻元素的差值不符合给定数据。
请你返回 符合 要求的隐藏数组的数目。如果没有符合要求的隐藏数组,请返回 0 。
示例 1:
输入:differences = [1,-3,4], lower = 1, upper = 6
输出:2
解释:符合要求的隐藏数组为:
- [3, 4, 1, 5]
- [4, 5, 2, 6]
所以返回 2 。
示例 2:
输入:differences = [3,-4,5,1,-2], lower = -4, upper = 5
输出:4
解释:符合要求的隐藏数组为:
- [-3, 0, -4, 1, 2, 0]
- [-2, 1, -3, 2, 3, 1]
- [-1, 2, -2, 3, 4, 2]
- [0, 3, -1, 4, 5, 3]
所以返回 4 。
示例 3:
输入:differences = [4,-7,2], lower = 3, upper = 6
输出:0
解释:没有符合要求的隐藏数组,所以返回 0 。
提示:
n == differences.length
- 1
<= n <= 105
- −105
<= differences[i] <= 105
- −105
<= lower <= upper <= 105
问题分析
-
前缀和(Prefix Sums)
定义
P0=0,Pi=k=0∑i−1differences[k](1≤i≤n).
则隐藏数组第 i 个元素有
hidden[i]=hidden[0]+Pi.
-
区间约束转化
要保证所有元素都在 [lower,upper] 之间,即对所有 0≤i≤n 都有
lower≤hidden[0]+Pi≤upper.
等价于
imax(hidden[0]+Pi)≤upper⟹hidden[0]≤upper−imaxPi,
imin(hidden[0]+Pi)≥lower⟹hidden[0]≥lower−iminPi.
hidden[0]≤upper−imaxPi,hidden[0]≥lower−iminPi.
-
可行起始值个数
记 minP=miniPi,maxP=maxiPi 。
那么
hidden[0]∈[lower−minP,upper−maxP],
区间长度(整数个数)为
( upper−maxP)−( lower−minP)+1=(upper−lower)−(maxP−minP)+1.
若该值为负,则答案是0。
算法思路
-
遍历一次 differences,用变量 curr 累加差分,实时维护 minP = min(minP, curr) 和 maxP = max(maxP, curr)。
-
根据上面推导,计算可行的 hidden[0] 的左端点 L = lower - minP,右端点 R = upper - maxP。
-
答案即为 max(0, R - L + 1)。
时间复杂度
代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| class Solution: def numberOfArrays(self, differences: List[int], lower: int, upper: int) -> int: minP = 0 maxP = 0 curr = 0 for d in differences: curr += d minP = min(minP, curr) maxP = max(maxP, curr) L = lower - minP R = upper - maxP return max(0, R - L + 1)
|
也可直接把对每个位置的区间约束(本质相同)
lower≤hidden[0]+Pi≤upper
转化为对 hidden[0] 的上下界,并在遍历中不断收缩,最终得出相同可行区间 [max{L},min{R}]
维护上下界
- 令
curr = P_i,初始 curr = 0。
- 看到新的
curr就把 hidden[0]≥lower−currents 转化为下界 L = lower - curr并往上取最大,把 hidden[0]≤upper−currents 转化为上界 R = upper - curr并往下取最小。
- 每步累加差分
curr += d 后
若 L > R 则 0,否则 R - L + 1。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| from typing import List
class Solution: def numberOfArrays(self, differences: List[int], lower: int, upper: int) -> int: curr = 0 L = lower R = upper for d in differences: curr += d candL = lower - curr if candL > L: L = candL candR = upper - curr if candR < R: R = candR return max(0, R - L + 1)
|