题目描述

✅ 413. 等差数列划分

image-20260928224014341

题意分析

统计长度至少为 3、相邻元素差值相同的连续子数组数量。不同起点或终点都算不同子数组,即使它们属于同一个较长等差段,也要分别计数;公差可以为 0 或负数。

解法:线性 DP 计数

核心思路

[!blue]

枚举每个子数组会重复检查很多差值。可以按右端点分组,用 cur 记录恰好以当前位置结尾的合法子数组数量,用 total 累加已经处理过的右端点贡献。

处理下标 i 时,比较 nums[i] - nums[i - 1] 和 nums[i - 1] - nums[i - 2]。若两者相等,原先以 i - 1 结尾的每个等差子数组都可以追加 nums[i],这些延长后的长度至少为 4;此外,末尾三个元素还新组成一个长度为 3 的等差子数组。因此新贡献为 cur + 1。

这个分类没有遗漏:以 i 结尾的合法子数组,要么恰好长 3,要么去掉最后一个元素后属于上一轮计数。两类长度不同,也不会重复。若末尾两个差值不同,连最后三个元素都不等差,更长的子数组也必然包含这处断裂,所以当前贡献必须归零。

每个子数组只有一个右端点,把每轮的 cur 加入 total 就能恰好统计全部答案。只需要上一轮的贡献,因此无需保存整张 DP 数组。

解题步骤

  1. 数组长度小于 3 时直接返回 0,否则初始化 cur = 0、total = 0。
  2. 从下标 2 开始比较末尾两个差值。
  3. 差值相同则先令 cur 加一,再把它加入 total。
  4. 差值不同则把 cur 清零,但保留已有的 total。
  5. 遍历结束后返回 total。

代码实现

class Solution {
    public int numberOfArithmeticSlices(int[] nums) {
        if (nums.length < 3) {
            return 0;
        }

        int total = 0;
        int cur = 0;

        for (int i = 2; i < nums.length; i++) {
            if (nums[i] - nums[i - 1] == nums[i - 1] - nums[i - 2]) {
                // 延长全部旧片段,再新增末尾三项组成的一段
                cur++;
                total += cur;
            } else {
                // 断裂只清当前末端贡献,保留累计总数
                cur = 0;
            }
        }

        return total;
    }
}
func numberOfArithmeticSlices(nums []int) int {
    if len(nums) < 3 {
        return 0
    }

    total := 0
    cur := 0

    for i := 2; i < len(nums); i++ {
        if nums[i]-nums[i-1] == nums[i-1]-nums[i-2] {
            // 延长全部旧片段,再新增末尾三项组成的一段
            cur++
            total += cur
        } else {
            // 断裂只清当前末端贡献,保留累计总数
            cur = 0
        }
    }

    return total
}

复杂度分析

  • 时间复杂度:$O(n)$,每个末端一次判断。
  • 空间复杂度:$O(1)$,当前贡献与累计总数。

关键点总结

[!green]

  • 当前变量是片段数量,不是等差段长度。
  • 差值保留符号,正一与负一不是相同公差。
  • 按右端点累加贡献,每个合法子数组既不会漏掉,也不会被算两次。

易错点总结

[!yellow]

  • 先累加再自增,会漏掉新出现的三项片段。
  • 断裂不清零,会把不同等差段连在一起。
  • 对差取绝对值,会把上升与下降的变化误认为相同公差。
  • 断裂时不能清空 total,此前结束的合法子数组仍然有效。

相似题目

题目 难度 关联与区别
446. 等差数列划分 II - 子序列 困难 本题要求连续区间,原题允许跳过元素形成子序列,需要按末项和公差累计状态。
1027. 最长等差数列 中等 同样围绕公差延续,原题求最长等差子序列,本题统计连续等差区间总数。
转载与许可
作者
链接 https://hgnulb.github.io/blog/2022/81248279
许可 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处!