在问 · 算法题解

414. 第三大的数

简单数组与矩阵一次遍历维护前三大力扣原题 ↗

题目描述

输入一个非空整数数组 nums。先去掉重复值,只看不同的数值,再从大到小排序。

如果不同的数值至少有三个,返回排第三的那个。否则返回其中最大的数。

示例 1
输入:nums = [3,2,1]
输出:1

解释:不同的数为 3、2、1,第三大是 1。

示例 2
输入:nums = [1,2]
输出:2

解释:只有两个不同的数,返回最大的 2。

示例 3
输入:nums = [2,2,3,1]
输出:1

解释:两个 2 只算一个值,不同的数为 3、2、1,第三大是 1。

数据范围

  • 1 <= nums.length <= 10^4
  • -2^31 <= nums[i] <= 2^31 - 1

进阶:能否在 O(n) 时间内完成?

解题思路:一次遍历维护前三大

一次遍历,维护三个槽位 a > b > c,分别是目前见过的第一、第二、第三大的不同数,空槽用 None 表示。对每个 x:如果它已经在槽位里,跳过;否则找到它应在的位置,把它后面的槽位依次往下挤一格,最小的被挤出去。结束时 c 非空就返回 c,否则返回 a。

为什么正确

处理完前 i 个数后,a、b、c 是 nums[0..i-1] 中最大的至多三个不同的数,且严格递减。

复杂度分析

时间 O(n),空间 O(1)。

易错点

重复的数只算一次,必须先判重再比较;不要用 -2^31 当“空”的哨兵,因为它本身可能就是第三大的数(如 [1,2,-2147483648]),C++/Java 里可用 long 的最小值。

参考代码

Python、Java、C++、Go、JavaScript、TypeScript 六种语言,逻辑一致。

class Solution:
    def thirdMax(self, nums: List[int]) -> int:
        a = b = c = None
        for x in nums:
            if x == a or x == b or x == c:
                continue
            if a is None or x > a:
                a, b, c = x, a, b
            elif b is None or x > b:
                b, c = x, b
            elif c is None or x > c:
                c = x
        return a if c is None else c

载入编辑器,自己跑一遍 →

其他解法

排序后按顺序数出第三个不同的数,简单但要 O(n log n);一次遍历只维护三个变量,时间 O(n)、空间 O(1)。

解法 2:排序 时间 O(n log n),空间 O(log n)

把数组降序排序。从前往后遍历,遇到和前一个元素不同的数时,不同数字计数加 1。计数到 3 时返回当前数。遍历结束仍不足 3 个不同数字时,返回最大值 nums[0]。

思路最直接,代码短。排序带来 O(n log n) 时间,并且会修改原数组。

class Solution:
    def thirdMax(self, nums):
        nums.sort(reverse=True)
        diff = 1
        for i in range(1, len(nums)):
            if nums[i] != nums[i - 1]:
                diff += 1
                if diff == 3:
                    return nums[i]
        return nums[0]

数组与矩阵 专题的其他题目

查看 数组与矩阵 全部题目 →