2026/1/11 4:34:36
网站建设
项目流程
云梦做网站的优势,电子产品采购平台,海南省建设执业资格注册管理中心网站,西青seo1 题目
3584. 子序列首尾元素的最大乘积
给你一个整数数组 nums 和一个整数 m。
返回任意大小为 m 的 子序列 中首尾元素乘积的最大值。
子序列 是可以通过删除原数组中的一些元素#xff08;或不删除任何元素#xff09;#xff0c;且不改变剩余元素顺序而得到的数组。…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] 1051 m nums.length2 代码实现思考根据以前的经验来看这种题目无非就是在迭代更新同时维护一个最大值但是在这里需要注意的是会出现负数。回忆一下我们买卖股票的代码。class Solution { public: int maxProfit(vectorint 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会超时因此需要优化对于每个可能的结尾位置j能和它配对的起始位置i必须满足i j - (m-1)。我们只需要在[0, j - (m-1)]这个范围内找到能让nums[i] * nums[j]最大的nums[i]即可。由于存在负数最大值可能来自最大的正数 × 正数最小的负数 × 负数负负得正可能更大自己写的代码错误百出class Solution { public: long long maximumProduct(vectorint 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 ; } };关键修改点说明问题类型错误代码行为修复后行为m1 逻辑错误初始化 maxNum0截断负数直接计算每个元素的平方遍历取最大值包含负数的平方边界覆盖不全只处理 i0 的情况漏掉 i0把计算逻辑移到 if 外i0 时直接用初始的 max_start/min_start 计算乘积逻辑错误计算 nums [i]*maxNum同位置相乘计算 max_startnums[j]/min_startnums [j]起始修正后通过的代码class Solution { public: long long maximumProduct(vectorint 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(i0)块内外部访问报错修复后移到块外确保全程可访问m1 逻辑错误初始化maxNum0截断负数直接赋值覆盖结果1. 取消maxNum0的错误初始化直接计算每个元素的平方2. 用max(max_val, square)迭代更新最大值而非直接赋值边界覆盖不全仅处理i0的情况漏掉i0的关键场景把乘积计算逻辑移出if(i0)块i0时用初始的max_start/min_start计算确保第一个有效jjm-1能被处理乘积逻辑错误错误计算nums[i]*maxNum同位置相乘修正为max_start*nums[j]/min_start*nums[j]起始位置最值 × 结尾位置值符合 “子序列首尾乘积” 的定义变量维护错误错误更新maxNummax(maxNum, nums[j])修正为max_startmax(max_start, nums[i_max])维护的是起始位置范围的最值而非结尾位置值二、核心反思点新手易踩坑 解题思路层面1. 对 “特殊场景” 的思考不足反思m1是题目中 “子序列首尾为同一个元素” 的特殊场景最初错误地用 “正数最大值” 的思路处理忽略了负数平方可能更大的特性。改进遇到 “乘积 / 平方” 类问题只要有负数参与必须优先考虑 “负负得正” 的情况不能默认只取正数。2. 对 “变量维护目标” 的理解模糊反思原代码混淆了 “维护起始位置的最值” 和 “维护结尾位置的值”错误地更新maxNum为nums[j]本质是没理清 “子序列首尾位置的约束关系”j - i m-1。改进解题前先明确 “维护的变量对应什么场景”—— 本题中max_start/min_start是 “所有能和j配对的起始位置i的最值”而非结尾位置的值。3. 对 “边界条件” 的验证不足反思原代码只处理i0的情况漏掉了i0第一个有效j本质是没验证 “循环第一次执行时的场景”。改进写循环逻辑时先手动代入第一个循环值如jm-1i0验证确认边界场景能被覆盖。4. 对 “变量作用域” 的基础认知不扎实反思最初将cur1/cur2定义在if块内导致外部访问报错是新手常见的语法漏洞。改进定义变量时先明确 “该变量是否需要跨块使用”跨块使用的变量需定义在块外或在块内完成所有相关计算。三、解题思路层面的核心总结本题的本质是 “找满足j - i m-1的(i,j)对计算nums[i]*nums[j]的最大值”而非暴力枚举子序列处理负数乘积时必须同时维护 “最大值” 和 “最小值”—— 最小值最负× 负数可能得到更大的正数特殊场景如m1需单独处理避免通用逻辑覆盖特殊情况。这些反思不仅能解决本题也适用于所有 “数组最值 负数参与运算” 的题目核心是先明确变量的语义再验证边界场景最后考虑负数的特殊运算规则。------概述一、核心反思特殊场景别漏判m1是首尾同元素的特殊情况需直接算元素平方取最大而非默认取正数再平方忽略负数平方的更大值。变量语义要盯死维护的maxNum/minNum是可配对的起始位置最值不是结尾位置值更新时要加起始位置的nums[i]而非nums[j]。边界条件先验证循环首次执行i0必须覆盖计算逻辑不能只放在i0的分支里否则会漏掉初始的有效配对。负数乘积双维护涉及乘积最值且有负数时要同时维护最大值和最小值 —— 负负得正可能出现更大结果只维护一个最值必错。二、同类题解题心法化繁为简抓本质子序列首尾配对问题 → 转化为满足j-i≥m-1的(i,j)对乘积最值避开暴力枚举子序列的坑。遍历一端护两端固定结尾j维护j左侧可配对范围的最值O (n) 遍历即可无需嵌套循环。负数乘积必双持只要有负数参与乘积最值计算必须同时维护当前范围的最大值和最小值两种乘积都要算。边界特殊先处理先解决m1等特殊情况再写通用逻辑避免特殊场景干扰正常流程。