当前位置: 首页 > news >正文

LeetCode算法日记 - Day 85: 等差数列划分

目录

1. 等差数列划分

1.1 题目解析

1.2 解法

1.3 代码实现


1. 等差数列划分

https://leetcode.cn/problems/arithmetic-slices/description/

如果一个数列 至少有三个元素 ,并且任意两个相邻元素之差相同,则称该数列为等差数列。

  • 例如,[1,3,5,7,9][7,7,7,7] 和 [3,-1,-5,-9] 都是等差数列。

给你一个整数数组 nums ,返回数组 nums 中所有为等差数组的 子数组 个数。

子数组 是数组中的一个连续序列。

示例 1:

输入:nums = [1,2,3,4]
输出:3
解释:nums 中有三个子等差数组:[1, 2, 3]、[2, 3, 4] 和 [1,2,3,4] 自身。

示例 2:

输入:nums = [1]
输出:0

提示:

  • 1 <= nums.length <= 5000
  • -1000 <= nums[i] <= 1000

1.1 题目解析

题目本质
统计数组中所有满足等差数列条件的连续子数组个数。核心是三个元素一组,根据条件判断是否合理。

常规解法
枚举所有可能的子数组(双重循环确定起点和终点),对每个子数组判断是否为等差数列。具体做法是:外层循环固定起点 i,内层循环遍历终点 j(j >= i+2),检查 nums[i...j] 是否等差。

// 暴力枚举法 - O(n³) 时间复杂度
static class Solution {public int numberOfArithmeticSlices(int[] nums) {int n = nums.length;if (n < 3) return 0;int count = 0;// 外层循环:固定起点 ifor (int i = 0; i < n - 2; i++) {// 内层循环:遍历终点 j(至少需要3个元素,所以 j >= i+2)for (int j = i + 2; j < n; j++) {// 检查子数组 nums[i...j] 是否为等差数列if (isArithmetic(nums, i, j)) {count++;}}}return count;}// 辅助函数:检查 nums[start...end] 是否为等差数列private boolean isArithmetic(int[] nums, int start, int end) {// 计算第一个差值作为基准int diff = nums[start + 1] - nums[start];// 检查后续所有相邻元素的差值是否都等于基准差值for (int k = start + 1; k < end; k++) {if (nums[k + 1] - nums[k] != diff) {return false;}}return true;}
}

问题分析
暴力枚举的时间复杂度是 O(n³)(双重循环 O(n²) × 等差判定 O(n)),对于 n=5000 的数据规模会超时。关键问题在于:大量重复计算了相邻元素的差值,没有利用"连续性"这个特点。

思路转折
等差数列有个重要性质——如果 [a,b,c] 是等差,且 [b,c,d] 也是等差(差值相同),那么 [a,b,c,d] 必然也是等差。这意味着我们可以用动态规划,记录"以当前元素结尾的等差子数组个数",通过前一个状态递推得到当前状态。这样只需要一次遍历 O(n),避免重复计算。

1.2 解法

算法思想:定义 dp[i] 表示以 nums[i] 结尾的等差子数组个数。当检查到第 i 个元素时,如果 nums[i] - nums[i-1] == nums[i-1] - nums[i-2](最近三个元素等差)
则有两种情况:

  • 新增一个长度为3的等差子数组:[nums[i-2], nums[i-1], nums[i]]

  • 所有以 nums[i-1] 结尾的等差子数组都可以向右扩展一位

递推公式:

dp[i] = dp[i-1] + 1  (当 nums[i]-nums[i-1] == nums[i-1]-nums[i-2])dp[i] = 0            (否则)

最终答案为所有 dp[i] 的和。

i)初始化 dp 数组(长度为 n)和结果变量 sum = 0

ii)从索引 i=2 开始遍历(因为至少需要3个元素)

iii)对于每个位置 i,计算差值:d1 = nums[i] - nums[i-1],d2 = nums[i-1] - nums[i-2]

iv)如果 d1 == d2,则 dp[i] = dp[i-1] + 1;否则 dp[i] = 0

v)累加 dp[i] 到 sum

vi)返回 sum

易错点:

  • 起始索引错误:循环必须从 i=2 开始,因为需要访问 nums[i-2]。从 i=0 或 i=1 开始会数组越界

  • 理解 dp[i] 的含义:dp[i] 不是"最长等差子数组长度",而是"以 i 结尾的等差子数组个数"。例如 dp[3]=2 表示有2个等差子数组以索引3结尾

  • 忘记累加结果:每次计算出 dp[i] 后要立即累加到 sum,不能只保存 dp[i] 最后再处理

  • 边界条件:当数组长度 < 3 时,直接返回0(题目要求至少3个元素)

1.3 代码实现

static class Solution {public int numberOfArithmeticSlices(int[] nums) {int n = nums.length;if (n < 3) return 0; // 少于3个元素无法构成等差数列int[] dp = new int[n]; // dp[i]: 以 nums[i] 结尾的等差子数组个数int result = 0;for (int i = 2; i < n; i++) {// 检查最近三个元素是否等差if (nums[i] - nums[i-1] == nums[i-1] - nums[i-2]) {// 可以扩展:继承 dp[i-1] 个 + 新增1个(最短的3元素数组)dp[i] = dp[i-1] + 1;}// 否则 dp[i] = 0(默认值)result += dp[i]; // 累加当前位置的贡献}return result;}
}

复杂度分析

  • 时间复杂度:O(n),只需遍历数组一次

  • 空间复杂度:O(n),使用了 dp 数组

http://www.dtcms.com/a/536745.html

相关文章:

  • Maven相关
  • 京东商品视频API:通过商品id商品链接获取商品的视频url
  • Maven快速上手笔记
  • 手机免费制作网站模板免费下载台州网站公司那里好
  • 企业网站哪家好网站流量超标
  • 钢结构网站建设网站建设必备
  • 数据分析综合应用实战:从统计分析到机器学习预测
  • 网站 源码 下载色无极网站正在建设中
  • 【测试理论和实践 2.测试概念】
  • 算法 day 36
  • 【论文阅读】图数据库 Survey: Graph Databases
  • 长沙优化网站关键词合肥政务新区建设局网站
  • 化学网站定制简网app工场怎么创app
  • 今天我们学习Linux架构中的Redis数据库基础
  • 网站商城系统教资报名网站设置
  • 引入实时 3D 渲染技术,地平线与 Unity 开启车载交互空间化时代
  • 用狸窝转换器转换视频后文件变大的问题排查
  • Ansible自动化部署Harbor私有仓库指南④
  • AI模型开发 | 基于AutoDL部署Deepseek OCR模型,从零打造OCR应用平台
  • 网站建设微金手指下拉15价目表app制作
  • 基于深度学习的户口本识别技术通过智能图像处理、文字定位和语义理解,实现99%以上的高精度识别
  • 在线视频教育网站开发公司注册资金最低多少
  • JVM学习第一章
  • Promise 详解
  • [nanoGPT] 性能与效率 | `torch.compile()` |`Flash Attention`|`混合精度训练`|`estimate_mfu`
  • 异常日志不打印堆栈?谈谈 JVM 的 Fast Throw
  • docker wordpressseo插件wordpress
  • 网站模板设计工具能引流的都有什么平台
  • CAD三维模型:超越形状的设计信息载体
  • RoboTwin 数据收集-翻译