首页 > 其他分享 >力扣-414. 第三大的数

力扣-414. 第三大的数

时间:2024-04-23 23:13:31浏览次数:29  
标签:414 nums int 复杂度 nullptr 第三 力扣 num &&

1.题目

题目地址(414. 第三大的数 - 力扣(LeetCode))

https://leetcode.cn/problems/third-maximum-number/

题目描述

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

 

示例 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) 的解决方案吗?

2.题解

2.1 排序(nlog(n))

思路

先排序,然后寻找是否有第三大的数,有则返回,没有则返回最大值
这里很有意思if(nums[i] != nums[i-1] && ++diff == 3), 判断条件使用了逻辑熔断,&&中 前者不成立,后面的语句便不会执行
也就是说,只有两个数不同时, 才会执行++diff, 避免了重复加的问题

代码

  • 语言支持:C++

C++ Code:


class Solution {
public:
    int thirdMax(vector<int>& nums) {
        sort(nums.begin(), nums.end(), greater<>()); // 默认排序是less<>()
        for(int i = 1, diff = 1; i < nums.size(); i++){
            if(nums[i] != nums[i-1] && ++diff == 3){ // 跳过了第一个元素,方便比较前后值
                return nums[i];
            }
        }
        return nums[0];
    }
};

复杂度分析

令 n 为数组长度。均为排序所需

  • 时间复杂度:\(O(nlogn)\)
  • 空间复杂度:\(O(logn)\)

2.2 Set集合

思路

思路很简单,利用set集合自动排序的功能,维持个数总是在3个较大值,输出最大数就是排头, 输出最小值就是排尾
这里set集合默认是less排序,也就是从小到大,我尝试了一下使用greater(变麻烦了)
尤其是在处理erase最后一个最小的元素时, 由于st.end()并不是指向最后一个元素, 而且erase似乎不接受st.rbegin(begin和end都是Iterator类型, rbegin和rend都是 reverse_iterator类型)
好在我们有一个函数prev, 可以求取指定迭代器的上一个迭代器

代码

class Solution {
public:
    int thirdMax(vector<int>& nums) {
        set<int, greater<int>> st;
        for(int num: nums){
            st.emplace(num);
            if(st.size() > 3){
                st.erase(prev(st.end()));
            }
        } 
        return st.size()<3?*st.begin():*st.rbegin();
    }
};

复杂度分析

令 n 为数组长度。

  • 时间复杂度:\(O(n)\)
  • 空间复杂度:\(O(1)\)

2.3 一次循环

思路

使用三个记录变量, 遍历一次数组, 不断更新最大的三个值, 最后判断结果即可
这里有个问题, 由于数据 -2^31 <= nums[i] <= 2^31 - 1
我们这里如果设置初始值为 INT_MIN 的话, 出现类似[1,2,-2147483648(INT_MIN)]的数据, 就会有c==INT_MIN 导致输出最大值发生错误
所以我们选择使用 LONG_MIN = -2147483648 和 long类型(这里两者不是相等吗?为何就可以了?) // TODO 不是很清楚为何

代码

class Solution {
public:
    int thirdMax(vector<int>& nums) {
        long a = LONG_MIN, b = LONG_MIN, c = LONG_MIN;
        for(long num : nums){
            if(num > a){
                c = b;
                b = a;
                a = num;
            } else if(num > b && num < a){
                c = b;
                b = num;
            } //else if(num > c && num != b){ 这里我们会下意识认为之前不是判断 num > b 不成立了吗, 这里肯定是 num <= b, 我们只要判断 num != b  就行了, 但是注意上面也有可能是不满足num < a 而下来的,如此判断便会出错 
            else if(num > c && num < b){
                c = num;
            }
        }
        return c == LONG_MIN ? a : c;
    }
};

复杂度分析

令 n 为数组长度。

  • 时间复杂度:\(O(n)\)
  • 空间复杂度:\(O(1)\)

2.4 一次循环(指针写法-无需考虑范围)

思路

既然使用int之流需要考虑范围,我们考虑使用指针,无穷小就用空指针来表示
注意:
1.这里必须使用&num, 填写num的真实地址, 而不是复制的地址, 因为在循环结束之后就会被释放,这是不可以的
2.使用熔断机制, 判断值为无穷小(nullptr) 还是有值 (空指针放前面,如果是则熔断,不会执行后面的a,b,*c导致空指针异常)
3.对于c的判断条件, 要小心这里仍然可能出现 b == nullptr的情况, 也就是 第二个if中, b==nullptr, 而 num == *a, 导致跳过(重复元素)

代码

class Solution {
public:
    int thirdMax(vector<int>& nums) {
        int *a = nullptr, *b = nullptr, *c = nullptr;
        for(int &num : nums){
            if(a == nullptr || num > *a ){
                c = b;
                b = a;
                a = &num;
            } else if(( b == nullptr || num > *b ) && num < *a){
                c = b;
                b = &num;
            } 
            else if(( c == nullptr || num > *c ) && b != nullptr && num < *b){ // 存在一种b==nullptr,但是num == *a的情况,这样会走到第三个if,但是b==nullptr导致空指针异常,所以加上判断
                c = &num;
            }
        }
        return c == nullptr ? *a : *c;
    }
};

标签:414,nums,int,复杂度,nullptr,第三,力扣,num,&&
From: https://www.cnblogs.com/trmbh12/p/18154044

相关文章

  • 力扣-495. 提莫攻击
    1.题目题目地址(495.提莫攻击-力扣(LeetCode))https://leetcode.cn/problems/teemo-attacking/题目描述在《英雄联盟》的世界中,有一个叫“提莫”的英雄。他的攻击可以让敌方英雄艾希(编者注:寒冰射手)进入中毒状态。当提莫攻击艾希,艾希的中毒状态正好持续 duration秒。正......
  • Meta 向第三方开放 MR 操作系统;黄仁勋:人形机器人成本可能比人们预期要低得多丨 RTE 开
       开发者朋友们大家好: 这里是「RTE开发者日报」,每天和大家一起看新闻、聊八卦。我们的社区编辑团队会整理分享RTE(RealTimeEngagement)领域内「有话题的新闻」、「有态度的观点」、「有意思的数据」、「有思考的文章」、「有看点的会议」,但内容仅代表编辑的个人观点......
  • 力扣-665. 非递减数列
    1.题目题目地址(665.非递减数列-力扣(LeetCode))https://leetcode.cn/problems/non-decreasing-array/题目描述给你一个长度为 n 的整数数组 nums ,请你判断在最多改变 1个元素的情况下,该数组能否变成一个非递减数列。我们是这样定义一个非递减数列的: 对于数组中任......
  • 【每周例题】力扣 C++ 分割字符串
    分割字符串题目 题目分析1.先确定用容器存储,容器的存储结构如下图所示: 2.这个题目的话,第一反应应该是用到动态规划,下面是动态规划的模板:res=[]ans=[]defbacktrack(未探索区域,res,path):if未探索区域满足结束条件:res.add(ans)#深度拷贝......
  • 10天冲刺第三天
    今天做了什么:把个人中心界面弄完了,因为其他活动界面还没做,就每个按钮功能姑且是跳转回主页面,名字和手机号是要用登录时缓存的数据这是个人中心页面代码<?xmlversion="1.0"encoding="utf-8"?><LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"......
  • 【每周例题】力扣 C++ 最小和分割
    最小和分割题目 题目分析1.num1 和 num2 中所有数字出现的次数之和等于 num 中所有数字出现的次数。即,num1与num2是从num中提取出来的,且不会重复提取同一个数字,且提取的顺序并不需要按照num的数字顺序2.返回 num1 和 num2 可以得到的和的最小值。要想得到最小值,需......
  • 最近对接通联支付第三方平台,支付成功后要回调方法告知支付是否成功,通知url必须为直接
    最近公司要做PC端,微信小程序端支付,对接的第三方是通联支付,因为需要用到回调方法,所以想到了natapp内网穿透的方法给通联支付提供回调的地址访问我本机项目第一步:打开natapp,注册账号https://natapp.cn/新手的话,需要购买免费隧道,不用花钱 我几年前已经申请账号也购买免费......
  • 《渣男代码历险记》第三章:天谴之子——光明与黑暗的对决
    “醒醒!醒醒!”“我这是在哪?”二。“你昏睡了34天了。”舅舅。“发生了什么?”舅舅哽咽了,半天说不出话来。“你。。。。。。是天谴之子。”“你为什么这样说?”“你只有放弃人类的未来,才能获得自身的幸福。现在全人类都被代码灭亡了。你答对一个计算机题目,就可以救若干个人类。......
  • 力扣周赛394之别样DP + 别样Dijkstra
    别样DP题目链接https://leetcode.cn/problems/minimum-number-of-operations-to-satisfy-conditions/description/题目大意题目思路需要考虑m列每一列填什么的情况,因为最终每一列都是一样的考虑暴力,每一列都可以变成0-9有\(10^m\)次种情况,这必然是不可行的我们从前往......
  • (复习)树上启发式合并(dsu on tree)入门U41492树上数颜色
    主要思想是树的重轻儿子之分使得时间复杂度为o(nlogn),神奇欲深入了解的这里:https://oi-wiki.org/graph/dsu-on-tree/点击查看代码#include<bits/stdc++.h>usingnamespacestd;typedefstructedge//边结构体{intto,next;}EDGE;//边相关数组EDGEe[100001<<1];......