点击获取AI摘要

3392. 统计符合条件长度为 3 的子数组数目 E

给你一个整数数组 nums ,请你返回长度为 3 的 子数组 的数量,满足第一个数和第三个数的和恰好为第二个数的一半。

子数组 指的是一个数组中连续 非空 的元素序列。

示例 1:

输入: nums = [1,2,1,4,1]

输出: 1

解释:

只有子数组 [1,4,1] 包含 3 个元素且第一个和第三个数字之和是中间数字的一半。number.

示例 2:

输入: nums = [1,1,1]

**输出: ** 0

解释:

[1,1,1] 是唯一长度为 3 的子数组,但第一个数和第三个数的和不是第二个数的一半。

提示:

  • 3 <= nums.length <= 100
  • -100 <= nums[i] <= 100

问题分析

输入:长度为 nn 的整数数组 nums,满足 3n1003 \le n \le 100,元素取值 [100,100][-100,100]

目标:统计所有长度恰好为 3 的连续子数组 [a,b,c][a,b,c],使得

a+c=b22(a+c)=b.a+c=\frac{b}{2}\quad\Longleftrightarrow\quad2(a+c)=b.

因为子数组长度固定且很小(仅 3),子数组个数仅 n2n-2,可线性枚举,每个子数组只涉及 3 个元素,检查条件恒为常数时间。

算法思路

  1. 初始化

    • 计数器 ans = 0
  2. 遍历“中间位置”

    • 令指针 ii 从 1 到 n2n-2(包含),那么第 ii 个元素就是子数组的中间元素 b=nums[i]b = \text{nums}[i]

    • 子数组的首尾分别是:

      a=nums[i1],c=nums[i+1].a = \text{nums}[i-1],\quad c = \text{nums}[i+1].

  3. 判断并累加

    • 检查条件:

      2×(a+c)==b.2 \times (a + c) == b.

    • 如果成立,ans += 1

  4. 返回结果

    • 遍历结束后,ans 即为满足条件的子数组数量。

时间复杂度

时间复杂度

  • 暴力枚举每个窗口需要 O(n)O(n) 次检查,其中 n=len(nums)n = \text{len}(nums),每次检查 O(1)O(1),只需一次线性遍历,整体 O(n)O(n)

空间复杂度

  • 仅使用常数级额外变量计数,O(1)O(1)

代码分解

1
2
3
4
5
6
7
8
9
10
function countSubarrays(nums):
ans ← 0
for i from 1 to length(nums)-2:
a ← nums[i-1]
b ← nums[i]
c ← nums[i+1]
if 2*(a + c) == b:
ans ← ans + 1
return ans

  • range(1, len(nums)-1):因为窗口长度固定 3,首元素索引为 i1i-1,尾元素索引为 i+1i+1,故 ii 取值区间为 [1,n2][1, n-2]

  • 每次循环只做一次加法、一次乘法、一次比较,都是 O(1)O(1) 操作。

代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from typing import List

class Solution:
def countSubarrays(self, nums: List[int]) -> int:
"""
统计所有长度=3 的连续子数组 [a, b, c] 满足 2*(a + c) == b。
时间复杂度:O(n),空间复杂度:O(1)。
"""
ans = 0 # 计数器,初始为 0

# i 从 1 到 len(nums)-2,确保 i-1, i, i+1 都在数组内
for i in range(1, len(nums) - 1):
a = nums[i - 1] # 子数组首元素
b = nums[i] # 子数组中间元素
c = nums[i + 1] # 子数组尾元素

# 判断核心条件:2*(a + c) == b
if 2 * (a + c) == b:
ans += 1 # 条件满足时,计数器加 1

return ans # 返回最终结果