统计特殊三元组-LeetCode
3583.统计特殊三元组
🎯 问题描述
描述:
给你一个整数数组 nums。
如果三元组 (i, j, k) 满足以下条件,我们称之为特殊三元组:
0 <= i < j < k < nnums[i] == 2 * nums[j]nums[k] == 2 * nums[j]
换句话说,中间元素 nums[j] 的两倍必须等于左边元素 nums[i] 和右边元素 nums[k]。
请你返回特殊三元组的数目。由于答案可能很大,请返回它对 取余的结果。
说明:
-
这是一个枚举中间点结合**动态计数(滑动窗口)**的问题。
-
核心策略:固定中间下标
j,我们需要快速知道j左侧有多少个2 * nums[j],以及j右侧有多少个2 * nums[j]。 -
优化点:不需要每次都重新遍历左右子数组。随着
j向右移动,我们只需要将元素从“右侧计数器”移动到“左侧计数器”即可。 -
示例:
-
示例 1:
1 | 输入:nums = [2, 1, 4, 1, 2] |
💻 解题思路
思路1:动态维护前后缀计数
核心逻辑
- 初始化计数器:
count2(右侧计数器):初始化为整个数组的频次统计。count1(左侧计数器):初始化为空(或者只包含第一个元素,视循环起点而定)。
- 枚举中间点
j:- 遍历
j从1到n-2。 - 关键操作:在检查
j之前,nums[j]实际上还属于“右侧”区域(或者刚要从右侧移除)。我们需要先将nums[j]从count2中减去,因为它即将成为中间点,不能再作为右边的k。
- 遍历
- 计算贡献:
- 目标值
target = nums[j] * 2。 - 检查
count1[target](左侧有多少个目标值)和count2[target](右侧有多少个目标值)。 - 累加
count1[target] * count2[target]。
- 目标值
- 更新左侧计数器:
- 处理完
j后,将nums[j]加入count1,因为它对于下一个中间点j+1来说,就变成了左侧元素。
- 处理完
代码实现
1 | class Solution: |
📊 性能分析
- 时间复杂度:
- 初始化
Counter需要 。 - 遍历数组一次,每次循环内的哈希表操作(加减、查找)都是 。
- 总时间复杂度为 。
- 初始化
- 空间复杂度:
- 两个哈希表
count1和count2最多存储 个键值对。
- 两个哈希表
思考
-
为什么这是 而不是 ?
- 上一题的解法在每次循环中都会重新切片并统计
Counter,这导致了 。 - 本题通过增量更新,每次只做常数次哈希表操作,避免了重复遍历子数组。
- 上一题的解法在每次循环中都会重新切片并统计
-
元素归属的流转:
- 每个元素
nums[x]的状态流转如下:- 初始:在
count2中。 - 当
j扫过它之前:作为右侧元素(候选k)。 - 当
j == x:从count2移除,作为中间元素(j)。 - 当
j > x:加入count1,作为左侧元素(候选i)。
- 初始:在
- 每个元素
-
边界处理:
- 代码在循环前手动处理了
nums[0],将其放入count1并从count2移除。这是为了保证循环从j=1开始时,左侧区域[0, 0]是正确的。 - 循环结束时
j = n-2,此时nums[n-1]还在count2中,作为右侧元素被正确统计。
- 代码在循环前手动处理了
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 笺札!






