LeetCode 每日一题笔记 日期:2025.12.15 题目:2110.股票平滑下跌阶段的数目

LeetCode 每日一题笔记

0. 前言

  • 日期:2025.12.15
  • 题目:2110.股票平滑下跌阶段的数目
  • 难度:中等
  • 标签:数组 数学 动态规划

1. 题目理解

问题描述

给你一个整数数组 prices ,表示一支股票的历史每日股价,其中 prices[i] 是这支股票第 i 天的价格。

一个 平滑下降的阶段 定义为:对于 连续一天或者多天 ,每日股价都比 前一日股价恰好少 1 ,这个阶段第一天的股价没有限制。

请你返回 平滑下降阶段 的数目。

示例

示例 1:

输入:prices = [3,2,1,4]

输出:7

解释:总共有 7 个平滑下降阶段:

3\], \[2\], \[1\], \[4\], \[3,2\], \[2,1\] 和 \[3,2,1

注意,仅一天按照定义也是平滑下降阶段。
示例 2:

输入:prices = [8,6,7,7]

输出:4

解释:总共有 4 个连续平滑下降阶段:[8], [6], [7] 和 [7]

由于 8 - 6 ≠ 1 ,所以 [8,6] 不是平滑下降阶段。
示例 3:

输入:prices = [5,4,3,2,1]

输出:15

解释:单个元素阶段有5个,两个连续元素的阶段有4个,三个的有3个,四个的有2个,五个的有1个,总计 5+4+3+2+1=15。

2. 解题思路

核心观察

  1. 基础性质:单个元素本身就是一个平滑下降阶段,因此初始结果至少为数组长度;
  2. 连续平滑下降段的规律 :若存在长度为 k 的连续平滑下降序列(如 [3,2,1],k=3),则该序列能贡献的额外阶段数为 k-1 + k-2 + ... + 1(即 k*(k-1)/2)。例如 k=3 时,额外贡献 2+1=3 个阶段([3,2]、[2,1]、[3,2,1]);
  3. 动态规划视角 :以第 i 天为结尾的平滑下降阶段数 dp[i],若 prices[i] = prices[i-1]-1,则 dp[i] = dp[i-1] + 1;否则 dp[i] = 1。总阶段数为所有 dp[i] 的和。

算法步骤

原有代码的算法步骤
  1. 初始化结果:将单个元素的阶段数(数组长度)计入结果;
  2. 遍历数组找连续段
    • 从第 i 个元素开始,向后遍历找到最长的连续平滑下降序列,记录序列长度 count
    • 计算该连续段能贡献的额外阶段数(count-1 + count-2 + ... + 1),并累加到结果;
    • 调整遍历索引,跳过已处理的连续段元素;
  3. 返回最终结果:累加所有额外阶段数后得到总数目。
官方题解的算法步骤(动态规划)
  1. 初始化res = 1(第一个元素的阶段数),prev = 1(以第一个元素结尾的阶段数);
  2. 遍历数组 :从第二个元素开始,判断是否满足平滑下降条件:
    • 满足则 prev += 1(以当前元素结尾的阶段数 = 前一个的阶段数 + 1);
    • 不满足则 prev = 1(仅当前元素自身);
    • 每次将 prev 累加到总结果 res
  3. 返回总结果

3. 代码实现

java 复制代码
class Solution {
  public static long getDescentPeriods(int[] prices) {
        long result=0;
        result+=prices.length;

        for (int i = 0; i < prices.length; i++) {
            int count=1;
            int a=  prices[i];
            i++;
            while (i<prices.length&&prices[i]==a-1){
                a=prices[i];
                i++;
                count++;
            }
             System.out.println("i:"+i);
             i-=1;
            System.out.println(count);
            //对count进行处理加入结果之中
            for (int j = count-1; j >0 ; j--) {
                result+=j;
            }
        }
        return result;
    }
}

4. 代码优化说明

原有代码的优缺点

  • 优点:逻辑直观,通过找连续段的方式直接计算贡献值,符合直观的数学理解;
  • 缺点
    1. 存在嵌套循环(内层 for 循环计算累加和),时间效率略低;
    2. 索引操作繁琐(多次 i++/i--),容易出错;
    3. 额外的 System.out 打印语句增加冗余;
    4. 累加和计算可优化为数学公式(count*(count-1)/2),替代内层循环。

官方题解的优化点

  1. 时间效率优化:去掉嵌套循环,单次遍历即可完成计算,时间复杂度从 O(n)(最坏)/ O(n²)(极端情况)降至严格 O(n);
  2. 空间优化 :无需额外存储,仅用两个变量(resprev)记录状态,空间复杂度 O(1);
  3. 逻辑简化:基于动态规划思想,避免复杂的索引调整和累加和计算,代码更简洁、不易出错;
  4. 数学等价性:动态规划的累加方式与「单个元素 + 连续段额外贡献」的计算方式完全等价,最终结果一致。

原有代码的小优化(不改变核心逻辑)

将内层累加循环替换为数学公式,减少循环次数:

java 复制代码
// 替换原有内层for循环
if (count > 1) {
    result += (long) count * (count - 1) / 2;
}

5. 复杂度分析

原有代码复杂度

  • 时间复杂度
    • 最好情况(无连续平滑下降段):O(n),仅遍历数组一次;
    • 最坏情况(全数组是连续平滑下降段):O(n)(外层遍历) + O(n)(内层累加循环),整体仍为 O(n);
    • 注:若累加和用嵌套循环实现,极端情况下看似 O(n²),但实际每个元素仅被处理一次,总操作数仍为 O(n)。
  • 空间复杂度 :O(1),仅使用常数个变量(resultcounta 等),无额外空间开销。

官方题解复杂度

  • 时间复杂度:O(n),仅单次遍历数组,所有操作均为常数级;
  • 空间复杂度 :O(1),仅使用 resprev 两个变量,空间效率最优。

6. 总结

题目核心

本题的核心是识别「连续平滑下降序列」的贡献规律,无论是直接计算连续段的额外贡献,还是用动态规划累加每个位置的阶段数,本质都是对「1+2+...+(k-1)」这一数学规律的应用。

关键知识点

  1. 数学规律 :长度为 k 的连续平滑下降序列,除了 k 个单个元素阶段,还能贡献 k*(k-1)/2 个多元素阶段;
  2. 动态规划思想:利用「以当前元素结尾的阶段数」推导下一个状态,避免重复计算,提升效率;
  3. 数据类型注意 :结果可能很大(如数组长度为 10⁵ 时,总阶段数可达 ~5×10⁹),需用 long 存储结果,防止整数溢出。

刷题启示

  1. 面对「计数类」数组问题,先找单个元素/基础情况的贡献,再分析连续段的规律,可大幅简化计算;
  2. 动态规划是优化「连续段计数」问题的常用手段,通过状态递推避免嵌套循环;
  3. 累加和类的计算优先使用数学公式(如等差数列求和),替代循环累加,提升代码效率和可读性;
  4. 索引操作需谨慎,原有代码中多次调整 i 的值容易引入 bug,优化时应尽量简化索引逻辑。
相关推荐
智者知已应修善业15 小时前
【求中位数】2024-1-23
c语言·c++·经验分享·笔记·算法
张人玉15 小时前
百度 AI 图像识别 WinForms 应用代码分析笔记
人工智能·笔记·百度
地平线开发者15 小时前
PTQ 量化数值范围与优化
算法·自动驾驶
sali-tec15 小时前
C# 基于halcon的视觉工作流-章68 深度学习-对象检测
开发语言·算法·计算机视觉·重构·c#
测试人社区-小明16 小时前
智能弹性伸缩算法在测试环境中的实践与验证
人工智能·测试工具·算法·机器学习·金融·机器人·量子计算
xqqxqxxq16 小时前
背单词软件技术笔记(V1.0核心版及V2.0随机挖字母)
笔记
罗西的思考16 小时前
【Agent】MemOS 源码笔记---(5)---记忆分类
人工智能·深度学习·算法
YJlio16 小时前
Active Directory 工具学习笔记(10.8):AdInsight——保存与导出(证据留存、共享与二次分析)
数据库·笔记·学习
xqqxqxxq17 小时前
背单词软件技术笔记(V2.0扩展版)
java·笔记·python