每日一题:第三大的数

地址

难度

简单

题目

给你一个非空数组,返回此数组中 第三大的数 。如果不存在,则返回数组中最大的数。

示例 1:

输入:[3, 2, 1]

输出:1

解释:第三大的数是 1 。

示例 2:

输入:[1, 2]

输出:2

解释:第三大的数不存在, 所以返回最大的数 2 。

示例 3:

输入:[2, 2, 3, 1]

输出:1

解释:注意,要求返回第三大的数,是指在所有不同数字中排第三大的数。 此例中存在两个值为 2 的数,它们都排第二。在所有不同数字中排第三大的数为 1 。

提示:

  • 1 <= nums.length <= 104
  • -231 <= nums[i] <= 231 - 1

进阶

你能设计一个时间复杂度 O(n) 的解决方案吗?

思路

  • 排序

题目是求第三大的数字,并且数组中有重复的数字。

先想到的就是利用 Set 去重,然后进行排序,取第三大的数字。

时间复杂度:O(nlogn),空间复杂度为 O(n)

class Solution {
    public int thirdMax(int[] nums) {
        // 去重
        Set<Integer> set = new HashSet<>();
        for (int i = 0; i < nums.length; i++) {
            set.add(nums[i]);
        }
        ArrayList<Integer> arrayList = new ArrayList<>(set);
        // 排序
        Collections.sort(arrayList);
        return arrayList.size() < 3 ? arrayList.get(arrayList.size() - 1) : arrayList.get(arrayList.size() - 3);
    }
}
  • 有序集合

利用 TreeSet 的特性。遍历数组,用一个TreeSet来维护数组中前三大的数。

具体做法是每遍历一个数,就将其插入有序集合,若有序集合的大小超过 3,就删除集合中的最小元素。这样可以保证有序集合的大小至多为 3,且遍历结束后,若有序集合的大小为 3,其最小值就是数组中第三大的数;若有序集合的大小不足 3,那么就返回有序集合中的最大值。

时间复杂度:O(n),空间复杂度为 O(n)。

TreeSet 的特性:

* TreeSet中存储的类型必须是一致的,不能一下存int,一下又存string
* TreeSet在遍历集合元素时,是有顺序的【从小到大】
* 排序:当向TreeSet中添加自定义对象时,有2种排序方法,1:自然排序 2、定制排序
* 没有带索引的方法,所以不能使用普通的for循环遍历
* 由于是set集合,所以不包含重复的集合
class Solution {
    public int thirdMax(int[] nums) {
        TreeSet<Integer> treeSet =new TreeSet<>();
        for(int x:nums){
            treeSet.add(x);
            if(treeSet.size()>3){
                treeSet.remove(treeSet.first());
            }
        }
        return treeSet.size()==3?treeSet.first():treeSet.last();
    }
}
  • 一次遍历

利用三个变量 a、b 和 c 来维护数组中的最大值、次大值和第三大值,以模拟方法二中的插入和删除操作。为方便编程实现,我们将其均初始化为 null。

遍历数组,对于数组中的元素 num:

若 num>a,我们将 c 替换为 b,b 替换为 a,a 替换为 num,这模拟了将 num插入有序集合,并删除有序集合中的最小值的过程

若 a>num>b,类似地,将 c 替换为 b,b 替换为 num,a 保持不变

若 b>num>c,类似地,将 c 替换为 num,a 和 b 保持不变

其余情况不做处理。

遍历结束后,若 ccc 仍然为 null,则说明数组中不存在三个或三个以上的不同元素,即第三大的数不存在,返回 a,否则返回 c。

class Solution {
    public int thirdMax(int[] nums) {
        Integer a = null, b = null, c = null;
        for (int x : nums) {
            if (a == null || x > a) {
                c = b;
                b = a;
                a = x;
            } else if (a > x && (b == null || x > b)) {
                c = b;
                b = x;
            } else if (b != null && b > x && (c == null || x > c)) {
                c = x;
            }
        }
        return c == null ? a : c;
    }
}