原题目
Given a non-empty array of integers, return the third maximum number in this array. If it does not exist, return the maximum number. The time complexity must be in O(n).
Example 1:
Input: [3, 2, 1]
Output: 1
Explanation: The third maximum is 1.
Example 2:
Input: [1, 2]
Output: 2
Explanation: The third maximum does not exist, so the maximum (2) is returned instead.
Example 3:
Input: [2, 2, 3, 1]
Output: 1
Explanation: Note that the third maximum here means the third maximum distinct number.
Both numbers with value 2 are both considered as second maximum.
题目大意
给定一个非空数组,找出第三大的数。值得注意的是:
- 若数组中有多个重复数字,在统计最大值的时候只算作一个
- 若第三大的数不存在,输出最大的数
- 算法的时间复杂度必须为O(n)
题解
int thirdMax(vector<int>& nums) {
long long a,b,c;
a = b = c = LLONG_MIN;
for(int num : nums)
{
if(num <= c || num == a || num == b) continue;
if(num > a)
{
c = b; b = a; a = num; continue;
}
if(num > b)
{
c = b; b = num; continue;
}
if(num > c)
{
c = num; continue;
}
}
return c == LLONG_MIN? a : c;
}
思路
- 本题的局限在于算法复杂度为O(n),因此最直观的做法是遍历向量中的所有元素,记录下最大,第二大,第三大的元素(a,b,c)
- 其中一个关键点在于a,b,c的初始化。由于在测试用例中包含了int范围中的所有数字,而要达到记录元素的目的,必须将三个数声明为long long,并都初始化为LLONG_MIN
- 解决了初始化问题之后,剩下的也很简单:
- 判断当前的数字是否与a,b,c任一一个有重复。如果有,跳过
- 判断当前的数字是否大于a,如果是的话,将原来的a,b,c依次向后推(递等),并令a为当前数字
- 对b同样进行上述的(判断+递等操作)
- 对c进行同样操作
- 最后根据c的值判断第三大的数是否存在(若存在的话c>LLONG_MIN),并根据判断结果输出
解法分析
在题目的讨论板块中,还给出了使用std::set的解法。这种解法的关键思路是利用了set是有序集并且能够去重的特性,完美地符合了题目的要求。但是从复杂度的角度来讲,构造集合其实也需要一定的计算。因此,从底层的角度出发,我认为这里不用set更加合理。