元素和最小的山形三元组II-LeetCode
2909. 元素和最小的山形三元组II
🎯 问题描述
描述:
给你一个下标从 0 开始的整数数组 nums。
请你找出并返回满足以下条件的最小三元组和:
- 存在下标 满足 。
- 满足“山形”条件: 且 。
- 目标是使 的值最小。
如果不存在这样的三元组,返回 -1。
说明:
-
这是一个前后缀分解(或预处理)的问题。
-
核心策略:我们可以枚举中间的元素 。
-
为了使总和最小,对于固定的 ,我们需要在 的左侧找到最小的 (满足 ),在 的右侧找到最小的 (满足 )。
-
通过预处理后缀最小值,我们可以将查找时间降低到 。
-
示例:
-
示例 1:
1 | 输入:nums = [5, 6, 1, 2, 3] |
💻 解题思路
思路1:后缀最小值 + 前缀动态维护
核心逻辑
- 预处理后缀最小值:
- 构建一个数组
suf,其中suf[i]表示nums[i...n-1]范围内的最小值。 - 这样,对于任意 ,我们可以在 时间内知道其右侧是否存在比它小的数(即
suf[j+1])。
- 构建一个数组
- 动态维护前缀最小值:
- 在遍历中间元素 时,用一个变量
pre记录nums[0...j-1]范围内的最小值。
- 在遍历中间元素 时,用一个变量
- 枚举中间点 :
- 遍历 从 到 。
- 检查是否满足“山形”条件:
pre < nums[j]且suf[j+1] < nums[j]。 - 如果满足,更新答案
ans = min(ans, pre + nums[j] + suf[j+1])。 - 更新
pre,供下一个 使用。
代码实现
1 | class Solution: |
📊 性能分析
- 时间复杂度:
- 其中 是
nums的长度。 - 构建后缀数组需要一次遍历 。
- 枚举中间点 需要一次遍历 。
- 总时间复杂度为 。
- 其中 是
- 空间复杂度:
- 需要一个长度为 的数组
suf来存储后缀最小值。
- 需要一个长度为 的数组
思考
-
为什么使用前缀最小值
pre和后缀最小值suf?- 题目要求 和 。
- 为了使总和 最小,在 固定的情况下,我们需要 和 尽可能小。
- 因此,对于每个 ,我们只需要考虑左侧的最小值和右侧的最小值。
-
后缀数组的构建:
suf[i] = min(suf[i+1], nums[i])。- 这保证了
suf[i]包含了从i到末尾的所有元素的最小值。 - 当我们检查 时,右侧的范围是 到 ,所以使用
suf[j+1]。
-
前缀变量的更新:
pre初始化为nums[0]。- 在每次循环结束时,
pre = min(pre, nums[j])。 - 这保证了当循环到 时,
pre存储的是nums[0...j]的最小值,正好是下一轮迭代的左侧范围。
-
边界条件:
- 的范围是 到 。
- 因为 至少为 0, 至多为 ,所以 不能是第一个或最后一个元素。
-
哨兵值:
ans初始化为3 * 10**8,这是根据题目约束(nums[i] <= 10^8)设定的一个足够大的数。- 最后通过比较
ans是否改变来判断是否找到了解。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 笺札!






