识别数组中的最大异常值-LeetCode
3371.识别数组中的最大异常值
🎯 问题描述
描述:
给你一个整数数组 nums。
数组中恰好包含一个异常值 ,其余 个元素的和可以表示为 (即剩余元素的和是偶数,且该和的一半 必须存在于剩余元素中)。
数学模型满足方程:
其中:
- 是我们要找的异常值。
- 是剩余元素中的某一个值(基准值)。
total是数组所有元素之和。
请你返回最大的异常值 。
说明:
- 这是一个哈希表计数结合方程变换的问题。
- 我们可以通过变换方程 ,得到两种不同的解题视角。
💻 解题思路
思路1:枚举异常值 x(正向思维)
核心逻辑
我们尝试假设数组中的每一个数都是异常值 。
- 假设当前数 被移除了。
- 计算剩余元素的和:。
- 根据方程,剩余元素的和必须等于 。这意味着:
- 必须是偶数。
- 剩余元素中必须包含数值 。
代码实现
1 | class Solution: |
优缺点分析
- 优点:符合直觉,直接寻找目标 。
- 缺点:需要处理奇偶性判断 (
% 2 == 0),逻辑稍微繁琐一点。
思路2:枚举基准值 y(逆向思维/方程变换)
核心逻辑
我们尝试假设数组中的每一个数都是基准值 。
- 利用方程变换:。
- 假设当前数 是基准值,我们直接计算出理论上对应的异常值 应该是多少。
- 检查计算出的 是否存在于剩余的数组中。
代码实现
1 | class Solution: |
优缺点分析
- 优点:逻辑更简洁。不需要判断奇偶性,直接计算并查找,代码更短,运行通常也稍快(少了一次取模运算)。
- 缺点:需要转个弯,意识到可以枚举 来求 。
📊 性能分析
- 时间复杂度:
- 两种思路都需要遍历数组一次构建哈希表,再遍历一次进行枚举。
- 哈希表操作均为 。
- 空间复杂度:
- 都需要
Counter来存储元素频次。
- 都需要
💡 深度思考
-
为什么要
cnt[val] -= 1?- 这是**“借用后归还”**的模式。
- 当我们假设当前的数是 (或 )时,它已经被“使用”了。
- 我们要查找的配对值( 或 )必须来自剩下的元素。
- 如果不减 1,当 时(例如数组
[3, 3, 3],total=9,x=3, y=3),程序可能会错误地认为当前的 自己就是那个 ,导致逻辑错误(除非该数字出现多次)。
-
为什么思路2更好?
- 思路1 是 。这隐含了约束 。
- 思路2 是 。这里 没有奇偶性约束,任何整数都可以。
- 消除约束通常能让代码更健壮、更简单。
-
数学之美:
- 同一个方程 ,既可以看作“已知 A 求 B”,也可以看作“已知 B 求 A”。在算法题中,灵活变换主元往往是优化的关键。
思路3:排序 + 贪心 + 二分查找
核心逻辑
前两种思路使用了哈希表,时间复杂度为 ,但需要遍历整个数组。
本思路利用排序和贪心策略:
- 排序:将数组从小到大排序。
- 贪心枚举:题目要求最大的异常值。因此,我们从数组末尾向前(从大到小)遍历。
- 二分查找:对于每一个假设的异常值 (代码中的
outlier):- 计算剩余和 。
- 若 为奇数,跳过。
- 若 为偶数,计算目标基准值 。
- 使用二分查找 (
bisect_left) 在数组中查找 。
- 去重验证:
- 如果找到了 ,需要确保 不是我们正在假设的 本身(除非数组中有多个 )。
- 由于数组已排序,相同的值会相邻。如果找到的 的索引与 的索引相同,我们需要检查相邻位置是否有相同的值。
代码实现
1 | import bisect |
📊 性能分析
- 时间复杂度:
- 排序耗时 。
- 遍历数组最坏情况下 。
- 每次遍历内部进行二分查找,耗时 。
- 总时间复杂度为 。
- 注:虽然比哈希表的 慢,但在实际运行中,如果最大的异常值恰好在数组末尾,这种方法可能更快返回(早停)。
- 空间复杂度: 或
- 取决于排序算法的实现(Python 的
sort是 Timsort,空间复杂度为 )。如果不计算排序空间,则为 。
- 取决于排序算法的实现(Python 的
💡 思考
-
贪心策略(早停机制):
- 题目要求最大的异常值。
- 哈希表方法必须遍历完整个数组才能确定最大值。
- 排序方法可以从大到小遍历,一旦找到合法的异常值,立即返回。在最好的情况下(最大值就是异常值),时间复杂度接近 (排序后直接二分一次)。
-
二分查找的优势:
- 将查找目标值 的时间从哈希表的 变成了 ,但换取了空间的节省(不需要哈希表)和逻辑的有序性。
-
复杂的去重逻辑:
- 这是排序方法的痛点。
- 在哈希表中,我们通过
cnt[val]--轻松处理了“借用”问题。 - 在排序数组中,我们需要通过索引来判断。
- 如果
k == i,说明我们想找的基准值 恰好就是当前的异常值 。 - 此时必须检查
nums[k-1]或nums[k+1]是否也等于 ,以确认数组中是否有另一个 可供使用。
-
对比三种思路:
- 思路1(枚举 x + 哈希):逻辑直观,但需处理奇偶性。
- 思路2(枚举 y + 哈希):逻辑最简,无奇偶判断,推荐。
- 思路3(排序 + 二分):空间换时间(实际上时间也变慢了),但具备“早停”潜力,适合数据量极大且异常值较大的情况。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 笺札!






