题目解析:
小M想通过查看往届比赛的排名,找到排名第三的分数作为自己的目标分数。具体规则如下:
- 如果有三个或以上不同的分数,返回其中第三大的分数。
- 如果不同的分数只有两个或更少,那么返回最大的分数。
我们的任务是,根据给定的分数数组,计算出小M的目标分数。
思路分析:
为了找到第三大的不同分数,我们需要处理以下两个问题:
- 消除重复分数: 因为题目要求的是不同的分数,所以需要去除数组中的重复元素。
- 找到第三大的分数: 在去重后的分数集合中,找到第三大的分数。如果不同分数的数量不足三,则返回最大的分数。
算法设计:
为了高效地解决这个问题,我们可以采取以下步骤:
-
使用数据结构去重:
- 集合(Set): 利用集合的性质,可以方便地去除重复元素。
- 优先队列(堆): 维护一个大小为3的最小堆,存储最大的三个不同分数。
-
遍历数组,更新前三大的分数:
- 使用变量跟踪: 使用三个变量
first、second、third,分别存储第一、第二、第三大的不同分数。 - 比较更新: 遍历数组时,比较当前分数与已存储的前三大分数,进行更新。
- 避免重复: 在更新过程中,确保不考虑已存在的分数。
- 使用变量跟踪: 使用三个变量
代码实现:
下面提供一种 时间复杂度为 O(n) 的解决方案,使用三个变量跟踪前三大的不同分数。
#include <vector>
#include <climits>
int findThirdMax(const std::vector<int>& nums) {
int64_t first = LLONG_MIN;
int64_t second = LLONG_MIN;
int64_t third = LLONG_MIN;
for (const int& num : nums) {
if (num == first || num == second || num == third) {
continue; // 跳过重复的分数
}
if (num > first) {
third = second;
second = first;
first = num;
} else if (num > second) {
third = second;
second = num;
} else if (num > third) {
third = num;
}
}
return third == LLONG_MIN ? static_cast<int>(first) : static_cast<int>(third);
}
代码解释:
-
第3行: 包含必要的头文件
vector和climits,后者用于使用LLONG_MIN。 -
第5行: 定义函数
findThirdMax,接受一个整数向量nums。 -
第6-8行: 初始化三个变量
first、second、third,分别为最小的 64 位整数LLONG_MIN,用于存储前三大的不同分数。 -
第10-17行: 遍历
nums数组,对于每个元素num:- 第11行: 如果
num已经等于first、second或third,则跳过,避免重复处理相同的分数。 - 第13-15行: 如果
num大于当前的first,则依次更新first、second、third。 - 第15-17行: 否则,如果
num大于second或third,则相应更新。
- 第11行: 如果
-
第19行: 如果
third仍然是初始值LLONG_MIN,说明不同的分数不足三个,返回最大的分数first;否则,返回第三大的分数third。
测试样例验证:
-
样例1:
输入:nums = [3, 2, 1] 输出:1- 处理后,前三大的分数分别为
first=3,second=2,third=1。 - 返回
third=1。
- 处理后,前三大的分数分别为
-
样例2:
输入:nums = [1, 2] 输出:2- 不同的分数只有两个,
first=2,second=1。 - 返回
first=2。
- 不同的分数只有两个,
-
样例3:
输入:nums = [2, 2, 3, 1] 输出:1- 去重后,分数为
[2, 3, 1]。 - 前三大的分数为
first=3,second=2,third=1。 - 返回
third=1。
- 去重后,分数为
知识总结:
- 变量跟踪法: 在需要找出前几大的元素时,可以使用有限的变量来跟踪,而不需要对整个数组进行排序,提高了效率。
- 注意边界值: 在初始化变量时,使用了
LLONG_MIN,确保能正确处理数组中包含最小整数的情况。 - 避免重复: 通过在遍历时跳过已存在的分数,保证了计算的是不同的分数。
学习方法与心得:
-
理解题意,明确要求:
- 在解题前,认真阅读题目,确保理解所有的要求和限制条件。
-
选择合适的数据结构和算法:
- 根据题目的时间和空间复杂度要求,选择最合适的解法。
- 本题中,通过变量跟踪的方法,避免了排序和额外的空间开销。
-
注意特殊情况的处理:
- 考虑数组中可能存在的重复元素,以及不同分数不足三个的情况。
-
代码实现中的细节:
- 使用
LLONG_MIN初始化变量,避免了与数组中的最小值冲突。 - 在比较时,注意先检查是否与已有的最大值重复。
- 使用
学习建议:
- 多练习经典问题: 例如寻找数组中的最大值、最小值、前几大元素等,熟悉不同的解法。
- 强化编程基本功: 熟练掌握编程语言中的数据类型和常量,例如
INT_MIN、LLONG_MIN等。 - 总结常用算法技巧: 例如使用变量跟踪法、哈希表、堆等,在不同的场景下灵活应用。
学习计划:
- 每日刷题: 利用豆包MarsCode AI刷题功能,坚持每天解答一道算法题,巩固所学知识。
- 错题归纳: 对于做错的题目,记录错误原因,定期复习,加强对薄弱环节的理解。
- 深入理解算法: 对于每道题目,不仅要会做,还要理解背后的算法思想和优化方法。
- 分享交流: 加入算法学习社区,与他人分享心得体会,互相学习。
工具运用:
- 豆包MarsCode AI刷题功能: 提供了丰富的题库和即时的反馈,帮助我们高效地练习算法题目。
- 结合其他资源: 如算法书籍、在线课程和技术博客,拓展知识面,学习不同的解题思路。
- 实践与应用: 在实际项目中尝试应用所学算法,加深理解,积累经验。
结语:
通过对这道题目的解析和学习,我们掌握了如何在不使用排序和额外空间的情况下,找到数组中第三大的不同元素。这不仅提高了我们的算法设计能力,也培养了我们细致考虑问题的习惯。希望我的学习方法和心得能对大家有所帮助,让我们一起在算法学习的道路上不断进步!