news 2026/4/3 6:31:45

Leetcode 91 子序列首尾元素的最大乘积

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Leetcode 91 子序列首尾元素的最大乘积

1 题目

3584. 子序列首尾元素的最大乘积

给你一个整数数组nums和一个整数m

返回任意大小为m子序列中首尾元素乘积的最大值

子序列是可以通过删除原数组中的一些元素(或不删除任何元素),且不改变剩余元素顺序而得到的数组。

示例 1:

输入:nums = [-1,-9,2,3,-2,-3,1], m = 1

输出:81

解释:

子序列[-9]的首尾元素乘积最大:-9 * -9 = 81。因此,答案是 81。

示例 2:

输入:nums = [1,3,-5,5,6,-4], m = 3

输出:20

解释:

子序列[-5, 6, -4]的首尾元素乘积最大。

示例 3:

输入:nums = [2,-1,2,-6,5,2,-5,7], m = 2

输出:35

解释:

子序列[5, 7]的首尾元素乘积最大。

提示:

  • 1 <= nums.length <= 105
  • -105 <= nums[i] <= 105
  • 1 <= m <= nums.length

2 代码实现

思考

根据以前的经验来看,这种题目无非就是在迭代更新,同时维护一个最大值,但是在这里需要注意的是会出现负数。

回忆一下我们买卖股票的代码。

class Solution { public: int maxProfit(vector<int>& prices) { int n = prices.size(); if (n == 0){ return 0 ; } int maxPro = 0 ; int minP = prices[0]; for (int i = 0 ; i < n ; i ++){ int curPro = prices[i] - minP; maxPro = max (maxPro ,curPro); minP = min( minP, prices[i]); } return maxPro; } };

其实我感觉这个题目有点像定长滑窗,长度是m,然后更新的值是乘积。

先自己写一下试试看吧!

不对不对,子序列不是滑动窗口,注意子序列是可以删除元素的!!!

啊,不知道怎么写。如果这个题是全部正数的就很简单了,但是有负数,不知道怎么维护。

----

ai老师登场。

问题

你现在需要解决的问题是:

给定整数数组nums和整数m,找到任意长度为m的子序列中首尾元素乘积的最大值。

核心难点在于子序列的特性(不改变顺序但可删元素)和存在负数的情况,这让直接暴力枚举所有可能的子序列变得不可行。

解题思路分析

首先明确核心逻辑:

  • 长度为m的子序列,其首尾元素在原数组中的位置满足j - i >= m - 1(即从原数组第i个元素到第j个元素,中间至少有m-1个元素,才能选出长度为m的子序列)。
  • 我们需要遍历所有满足条件的(i, j)对,计算nums[i] * nums[j],并找到最大值。
  • 由于数组长度可达1e5,暴力枚举所有i,j会超时,因此需要优化:
    1. 对于每个可能的结尾位置j,能和它配对的起始位置i必须满足i <= j - (m-1)
    2. 我们只需要在[0, j - (m-1)]这个范围内,找到能让nums[i] * nums[j]最大的nums[i]即可。
    3. 由于存在负数,最大值可能来自:
      • 最大的正数 × 正数
      • 最小的负数 × 负数(负负得正,可能更大)

自己写的代码错误百出

class Solution { public: long long maximumProduct(vector<int>& nums, int m) { int n = nums.size(); long long max_val = LLONG_MIN; if (m == 1){ for(int i = 0 ; i < n ; ++i){ long long maxNum = 0 ; maxNum = max(maxNum , (long long)nums[i]); max_val = maxNum * maxNum ; } return max_val; } long long maxNum = nums[0]; long long minNum = nums[0]; long long res = LLONG_MIN; for (int j = m - 1 ; j < n ; j++){ int i = j - m +1 ; if (i > 0){ maxNum = max(maxNum , (long long)nums[i]); minNum = min(minNum , (long long)nums[i]); long long cur1 = (long long)nums[i] * maxNum ; long long cur2 = (long long)nums[i] * minNum ; res = max(max(cur1 , cur2) , res); } } return res ; } };

关键修改点说明

问题类型错误代码行为修复后行为
m=1 逻辑错误初始化 maxNum=0,截断负数直接计算每个元素的平方,遍历取最大值(包含负数的平方)
边界覆盖不全只处理 i>0 的情况,漏掉 i=0把计算逻辑移到 if 外,i=0 时直接用初始的 max_start/min_start 计算
乘积逻辑错误计算 nums [i]*maxNum(同位置相乘)计算 max_startnums[j]/min_startnums [j](起始

修正后通过的代码

class Solution { public: long long maximumProduct(vector<int>& nums, int m) { int n = nums.size(); long long max_val = LLONG_MIN; if (m == 1){ for(int i = 0 ; i < n ; ++i){ long long square = (long long )nums[i] * nums[i]; max_val = max(square ,max_val); } return max_val; } long long maxNum = nums[0]; long long minNum = nums[0]; long long res = LLONG_MIN; for (int j = m - 1 ; j < n ; j++){ int i = j - m +1 ; if (i > 0){ maxNum = max(maxNum , (long long)nums[i]); minNum = min(minNum , (long long)nums[i]); } long long cur1 = (long long)nums[j] * maxNum ; long long cur2 = (long long)nums[j] * minNum ; res = max(max(cur1 , cur2) , res); } return res ; } };

3 小结

反思

看起来很恐怖的代码(至少在过去的我看来比较麻烦),但实际上思路很清晰。

case 1 : 如果m给的长度是1 ,那么就是找一个最大平方,这里我原先还弄错了变成了找最大的数,再平方。

case 2 : m给的长度大于1 ,相当于我要在一个m长度的序列里面找到最大的乘积,这里采用的是j作为循环遍历,其实用i也是一样的。

判断i是否大于0 ,就是在判断是否还有余下的序列更新。所有注意更新的循环放在里面,但是计算的逻辑放在循环外面。(这里我又弄错)

计算两个cur ,处理存在负数,负负得正的情况。

---------

修改

一、核心修改点(按优先级排序)

类别原代码问题修复方案
编译 / 作用域无(本次修改后解决了编译问题,但核心是逻辑)- 原代码曾将cur1/cur2定义在if(i>0)块内,外部访问报错;修复后移到块外,确保全程可访问
m=1 逻辑错误初始化maxNum=0截断负数,直接赋值覆盖结果1. 取消maxNum=0的错误初始化,直接计算每个元素的平方;2. 用max(max_val, square)迭代更新最大值,而非直接赋值
边界覆盖不全仅处理i>0的情况,漏掉i=0的关键场景把乘积计算逻辑移出if(i>0)块,i=0时用初始的max_start/min_start计算,确保第一个有效jj=m-1)能被处理
乘积逻辑错误错误计算nums[i]*maxNum(同位置相乘)修正为max_start*nums[j]/min_start*nums[j](起始位置最值 × 结尾位置值),符合 “子序列首尾乘积” 的定义
变量维护错误错误更新maxNum=max(maxNum, nums[j])修正为max_start=max(max_start, nums[i_max]),维护的是起始位置范围的最值,而非结尾位置值

二、核心反思点(新手易踩坑 + 解题思路层面)

1. 对 “特殊场景” 的思考不足
  • 反思:m=1是题目中 “子序列首尾为同一个元素” 的特殊场景,最初错误地用 “正数最大值” 的思路处理,忽略了负数平方可能更大的特性。
  • 改进:遇到 “乘积 / 平方” 类问题,只要有负数参与,必须优先考虑 “负负得正” 的情况,不能默认只取正数。
2. 对 “变量维护目标” 的理解模糊
  • 反思:原代码混淆了 “维护起始位置的最值” 和 “维护结尾位置的值”,错误地更新maxNumnums[j],本质是没理清 “子序列首尾位置的约束关系”(j - i >= m-1)。
  • 改进:解题前先明确 “维护的变量对应什么场景”—— 本题中max_start/min_start是 “所有能和j配对的起始位置i的最值”,而非结尾位置的值。
3. 对 “边界条件” 的验证不足
  • 反思:原代码只处理i>0的情况,漏掉了i=0(第一个有效j),本质是没验证 “循环第一次执行时的场景”。
  • 改进:写循环逻辑时,先手动代入第一个循环值(如j=m-1i=0)验证,确认边界场景能被覆盖。
4. 对 “变量作用域” 的基础认知不扎实
  • 反思:最初将cur1/cur2定义在if块内,导致外部访问报错,是新手常见的语法漏洞。
  • 改进:定义变量时先明确 “该变量是否需要跨块使用”,跨块使用的变量需定义在块外,或在块内完成所有相关计算。

三、解题思路层面的核心总结

  1. 本题的本质是 “找满足j - i >= m-1(i,j)对,计算nums[i]*nums[j]的最大值”,而非暴力枚举子序列;
  2. 处理负数乘积时,必须同时维护 “最大值” 和 “最小值”—— 最小值(最负)× 负数可能得到更大的正数;
  3. 特殊场景(如m=1)需单独处理,避免通用逻辑覆盖特殊情况。

这些反思不仅能解决本题,也适用于所有 “数组最值 + 负数参与运算” 的题目,核心是:先明确变量的语义,再验证边界场景,最后考虑负数的特殊运算规则

------

概述

一、核心反思

  1. 特殊场景别漏判m=1是首尾同元素的特殊情况,需直接算元素平方取最大,而非默认取正数再平方,忽略负数平方的更大值。
  2. 变量语义要盯死:维护的maxNum/minNum可配对的起始位置最值,不是结尾位置值,更新时要加起始位置的nums[i],而非nums[j]
  3. 边界条件先验证:循环首次执行(i=0)必须覆盖,计算逻辑不能只放在i>0的分支里,否则会漏掉初始的有效配对。
  4. 负数乘积双维护:涉及乘积最值且有负数时,要同时维护最大值和最小值 —— 负负得正可能出现更大结果,只维护一个最值必错。

二、同类题解题心法

  1. 化繁为简抓本质:子序列首尾配对问题 → 转化为满足j-i≥m-1(i,j)对乘积最值,避开暴力枚举子序列的坑。
  2. 遍历一端护两端:固定结尾j,维护j左侧可配对范围的最值,O (n) 遍历即可,无需嵌套循环。
  3. 负数乘积必双持:只要有负数参与乘积最值计算,必须同时维护当前范围的最大值和最小值,两种乘积都要算。
  4. 边界特殊先处理:先解决m=1等特殊情况,再写通用逻辑,避免特殊场景干扰正常流程。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/21 18:22:28

diskinfo下载官网之外的选择:用TensorFlow镜像监控存储性能

diskinfo下载官网之外的选择&#xff1a;用TensorFlow镜像监控存储性能 在AI训练任务日益复杂的今天&#xff0c;一个常被忽视的问题正在悄悄拖慢整个流程——数据读取的瓶颈。你有没有遇到过这样的情况&#xff1a;GPU利用率长期徘徊在30%以下&#xff0c;明明模型设计没问题&…

作者头像 李华
网站建设 2026/4/2 15:03:44

pot-desktop跨平台翻译终极指南:从安装配置到实战精通

pot-desktop跨平台翻译终极指南&#xff1a;从安装配置到实战精通 【免费下载链接】pot-desktop &#x1f308;一个跨平台的划词翻译和OCR软件 | A cross-platform software for text translation and recognize. 项目地址: https://gitcode.com/pot-app/pot-desktop 在…

作者头像 李华
网站建设 2026/4/2 18:52:33

在云服务器上部署TensorFlow-v2.9镜像的完整步骤(含SSH连接图解)

在云服务器上部署 TensorFlow-v2.9 镜像的完整实践指南 在深度学习项目启动阶段&#xff0c;最让人头疼的往往不是模型设计本身&#xff0c;而是环境配置——“为什么代码在我机器上能跑&#xff0c;换台设备就报错&#xff1f;”这类问题几乎每个开发者都经历过。依赖冲突、CU…

作者头像 李华
网站建设 2026/3/27 6:21:12

利用Transformer模型详解类文章吸引精准AI开发者用户群

利用Transformer模型详解类文章吸引精准AI开发者用户群 在当今AI研发节奏日益加快的背景下&#xff0c;一个常见的工程困境正困扰着许多团队&#xff1a;新成员入职三天&#xff0c;还在折腾CUDA版本和Python依赖&#xff1b;两个开发者跑同一段代码&#xff0c;训练结果却因环…

作者头像 李华
网站建设 2026/3/28 7:23:39

如何快速掌握Android网络调试:自定义过滤器的终极指南

如何快速掌握Android网络调试&#xff1a;自定义过滤器的终极指南 【免费下载链接】AndroidHttpCapture AndroidHttpCapture网络诊断工具 是一款Android手机抓包软件 主要功能包括&#xff1a;手机端抓包、PING/DNS/TraceRoute诊断、抓包HAR数据上传分享。你也可以看成是Androi…

作者头像 李华
网站建设 2026/3/27 13:48:33

用GitHub托管代码 + TensorFlow镜像运行 完美开发闭环

用 GitHub 托管代码 TensorFlow 镜像运行&#xff1a;构建现代 AI 开发闭环 在深度学习项目中&#xff0c;你是否曾遇到过这样的场景&#xff1f;——同事兴奋地告诉你他跑通了一个新模型&#xff0c;结果你在本地尝试复现时却报错不断&#xff1a;“CUDA 版本不兼容”、“Ten…

作者头像 李华