【LeetCode】128. 最长连续序列——哈希的应用(3)

news2024/11/26 2:46:11

文章目录

  • 1、思路
  • 2、解题方法
  • 3、复杂度
    • 时间复杂度:
    • 空间复杂度:
  • 4、Code

Problem: 128. 最长连续序列

在这里插入图片描述

1、思路

我会用一种做题者的思路来去看待这道题。

我们在乍一看到这道题的时候,看到它的时间复杂度要求为O(N),然后又要求去找序列(就是让你判断这个数的前面一个数在不在这个数组里,这个数的后面一个数在不在数组里)。按照我们平时暴力的做法(也是最先想到的做法),遍历一个O(N),然后判断每个元素在不在又是O(N),然后有可能会有N个元素,这样N* N *N最坏的情况就都有可能是O(N^3)了。要我们找序列,又要我们O(N),这不扯淡么。

因为所谓O(N)的复杂度,就是要让你一遍过,或者你能说出来几遍过(也即常数个O(N),即O(kN),k为常数),所以,我们说要你说常数遍过就有些扯淡了。

这个时候,我们就可以想到用时间换空间的思想。 并且,用哈希表的存储这样一个空间,来换遍历查找的时间,是一个非常暴力且不要脸的做法(但是并不妨碍我说这种做法好哈哈哈哈)。说它不要脸,是因为它简单易行。

什么意思?简单举个例子:假如有个数组,你要找比某个元素大1(或者小1)的元素在不在该数组里面,按照最粗暴的方法,那么你需要遍历整个数组,也就是O(N)的时间复杂度。但是如果你用哈希的话,那就变成O(1)啦

那么,现在对于数组内的每一个元素,我都要去找比它小1的元素在不在该数组里,如果按照原来的方法,我需要O(N*2)的时间复杂度。但是如果我用了哈希表,我就一下子变成了O(N)了。

没用什么多难的思想(即没有怎么多人为的操作,参见DP的某些题目),但是就轻轻松松完成了复杂度由时间向空间的转化。所以说,它很不要脸哈哈哈哈哈。

我们就是用这样一个核心的思想来去做这道题。

2、解题方法

在一开始拿到这道题,并且明确了哈希表有这样一个功能之后,最先想到的,是用unordered_map这样一个结构。因为不是要O(N)嘛,我是用哈希来去降了一次,但是我似乎遍历一遍数组需要O(N),但还需要去递归地去找 比每个元素小1的、小2的、小3的…小n的 在不在里面,这不是还是有个O(N)吗,然后合在一块不还是O(N^2)?

然后我想着,前面的第一次O(N)是不可避免的(因为你总要遍历整个数组嘛)。但是后面的那个O(N),可不可以用unordered_map里的 <key, value>来去标记我每个元素有没有遍历过呢?如果说,我在某次找比某个元素小1的、小2的…小n的时候遍历过了,那么我在第一个遍历数组的那个O(N)循环里就不需要再去遍历它了,但是这就有可能造成新的问题,就是我怎么知道谁是最长的呢?比如对于样例:

[100, 4, 200, 1, 3, 2, 5]

如果在外层第一层循环遍历到4的时候,我依靠哈希在内层找到了后面的1,2,3,并且标记它们已经被遍历过。那后面第一层循环再遍历到数组1,2,3的时候就直接跳过。但是如果我后面的5来了,我该怎么办呢?而且我这个时候4已经遍历过了。

如果大家能够明白我上面想表达的意思了,那么大家可以先不着急往下看,自己想一想该如何做。

其实做法有很多啦。在这里呢,就说两种。

1.是采用计数的方法。我们刚刚不是用了unordered_map嘛,那就可以在value中来去存储长度的相关信息。这样,在5来了之后,将它现在已有的长度加上4中的value中存储的长度,作为5的长度来使用。

2.这个做法就更加简单粗暴了就是如果这个数不是边界,就别理它,只有当它是边界的时候我们再去给它计数。什么意思呢?就是说,假如我们在内循环中,往比每个数小的那个方向去找(就是对于每个元素,我们统一找比它小1的、小2的、小3的…,而不是大1的,大2的,大3的…),那么如果我们能在该数组中找到有比它大1的元素存在,我们就直接跳过它,就不理它。直到我们在数组中不能够找到有比它大的元素存在,说明它就是边界了,这时我们才开始计数。

这里笔者就对第二种思路进行展开分析了哈。可以确立以下思路:

1)先把数组中所有的数都放到哈希表里面,直接放。

2)然后用几个 if 和 else 就搞定了

然后,对于数组的每一个元素,如果它的value值不是false(一开始初始化的时候都是true),\
判断每个数比它大1的和比它小1的是否在里面
if 比它大1:  
    if 它的比它大1没有在这数组里面(也就是不存在):
        then 它是最后一个元素 从它开始计数;再开始判断比它小1的数是否存在
        【
            if 比它小1的数在这里面 :
                then 继续往前找(找小2的、小3的...),并且找的那个元素的\
                value值赋值false,这样在外层“对于每一个元素中”看到它就会直接跳过了。 
            else:
                就不管,跳过
        】
    else if 比它大1的数在这里面:
        then 它不是最后一个元素,别理它,直接跳过

但是我又发现,这个false赋值的好像很鸡肋的样子。因为你会发现最后所有的value值是false的元素,都是"比它大1的数"存在的。那当我在外层循环遍历到这个value值是false的元素的时候,如果跟我不用这个false,我直接去找比它大1的数存不存在,如果存在,那我也仍然是可以直接跳过它,这个查找的时间复杂度也是O(1)。

所以这个false就完全没有必要了。在外层循环,我只要去找比它大1的元素存不存在就行了。实际上我在上述的伪代码中已经去找比它大1的数在不在了。

也就是说,思路简而言之,一句话:对于数组的每个元素,查找:1)比它大1的数不在里面,2)比它小1的数在里面,只有当1)2)条件都满足的时候,我们才开始内循环遍历(就是去找比它小1的、小2的…小n的在不在这里面),否则直接跳过该元素。然后最后找到最长的序列。

3、复杂度

时间复杂度:

以算法的角度来看,

1、把这些数放到哈希表里面,需要O(N);(步骤1)

2、再次遍历一个数组,也是O(N)。 (步骤2)

3、对于哈希表中的每个元素,如果它前一个数不在里面,直接跳过,O(1)。如果在里面,那么会递归去找之前的数,O(N),但是,可以预见这些数在未来的过程(步骤2)中就不会再次去遍历了。

因此是时间复杂度是 O ( N ) O(N) O(N)

不过很多人觉得这种说法可能会有些牵强,那我们换一种说法:

以数组中每个数的视角来去看,它最多会被遍历四次(放进哈希表一次,外层遍历一次,内层遍历一次,被来自比它小1的那个数的查找一次)

这样的话,就显然是 O ( N ) O(N) O(N)了。

空间复杂度:

O ( n ) O(n) O(n),哈希表的空间复杂度,没什么好说的。

4、Code

C++版本:

class Solution {
public:
    int longestConsecutive(vector<int>& nums) {
        int Max = 0;
        unordered_set<int> mp;
        for(int i = 0;i < nums.size();i++){
            mp.insert(nums[i]);
        }
        for(int i = 0;i < nums.size();i++){
            if(mp.find(nums[i] + 1) == mp.end()){
                int length = 1;
                while(mp.find(nums[i] - length) != mp.end()){
                    length++;
                }
                Max = max(Max, length);
            }
            else{
                continue;
            }
        }
        return Max;
    }
};

Java版本:

class Solution {
    public int longestConsecutive(int[] nums) {
        int max = 0;
        HashSet<Integer> set = new HashSet<>();
        
        for (int num : nums) {
            set.add(num);
        }
        
        for (int num : nums) {
            if (!set.contains(num + 1)) {
                int length = 1;
                
                while (set.contains(num - length)) {
                    length++;
                }
                
                max = Math.max(max, length);
            }
        }
        
        return max;
    }
}

Python版本:

class Solution(object):
    def longestConsecutive(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        max_length = 0
        num_set = set(nums)
        
        for num in nums:
            if num - 1 not in num_set:
                length = 1
                
                while num + length in num_set:
                    length += 1
                    
                max_length = max(max_length, length)
        
        return max_length

最后,可以来稍微总结一下,这道题的核心或者价值我认为还是在于用哈希来空间换时间的做法。如果不用哈希,那么判断前一个数在不在里面,将会用到O(N);判断后一个数在不在里面,也需要O(N),那么如果用哈希来查找,这两步的操作就都变成O(1)了->数组的频繁查找工作。至于后面的微调,我们有哈希表,于是乎大家只要去从“第一次遍历过的,第二次就不要遍历了”的角度去考虑就行了,也因为有哈希表,也就能有了这样考虑的余地。顺理成章地就出来了。

如果喜欢我的题解,就给我个关注吧,我会持续为大家带来更优质的分享。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1265032.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

高频Latex公式速查表,写论文技术博客不愁了

常见上下标X_{2}X^{2}\hat{X}\bar{X}\frac{1}{X}常见希腊字母\alpha \beta \gamma \delta \varepsilon \eta \theta \rho \sigma \phi \varphi \omega常见数学符号\leq \geq \neq\approx 其他\sum \prod \int \bigoplus \forall \exists \times \setminus \bigotimes \bigodot …

五分钟 k8s 实战-应用探针

Probe.png 今天进入 kubernetes 的运维部分&#xff08;并不是运维 kubernetes&#xff0c;而是运维应用&#xff09;&#xff0c;其实日常我们大部分使用 kubernetes 的功能就是以往运维的工作&#xff0c;现在云原生将运维和研发关系变得更紧密了。 今天主要讲解 Probe 探针相…

集成IDE开发环境,Java开发工具IntelliJ IDEA 2023中文

IntelliJ IDEA 2023是一款功能强大的软件&#xff0c;其为程序员提供了一款先进的集成开发环境。它以智能、高效和人性化为主要特点&#xff0c;致力于提高开发人员的生产力&#xff0c;帮助程序员更快、更好地编写代码。IntelliJ IDEA 2023支持多种语言和框架&#xff0c;包括…

iOS 通用链接的配置(Universal Links)

一、打开Associated Domains 1.首先登录 苹果开发者网站 2.Certificates, Identifiers & Profiles 下的Identifiers 找到要配追的Identifiers 点进去 3.打开Associated Domains然后保存 二、更新Profile文件 如果我们使用自动的&#xff0c;可以忽略这一步&#xff0c;…

泛微E-Office SQL注入漏洞复现

0x01 产品简介 泛微E-Office是一款标准化的协同 OA 办公软件&#xff0c;泛微协同办公产品系列成员之一,实行通用化产品设计&#xff0c;充分贴合企业管理需求&#xff0c;本着简洁易用、高效智能的原则&#xff0c;为企业快速打造移动化、无纸化、数字化的办公平台。 0x02 漏…

00.本地搭建 threejs 文档网站(网页版是外网比较慢)

three官网 https://threejs.org/ 下载代码 进入官网 可以选择github去下载 或者 下载压缩包 github 下载https链接地址 https://github.com/mrdoob/three.js.git git clone https://github.com/mrdoob/three.js.git安装依赖启动程序 安装依赖 npm i 或者 pnpm i 或者 …

通过git上传文件到github仓库

一、新建github仓库 访问github官网&#xff1a;GitHub: Let’s build from here GitHub 点击个人头像&#xff0c;在右侧栏选择Your repositories。 点击New&#xff0c;新建一个github仓库。 创建Repository name仓库名&#xff0c;如果这个仓库名已经创建过的话&#xff…

开始使用Spring Boot Admin吧-使用Nacos注册SBA

什么是 Spring Boot Admin&#xff08;SBA&#xff09;? Spring Boot Admin 是 codecentric 公司开发的一款开源社区项目&#xff0c;目标是让用户更方便的管理以及监控 Spring Boot 应用。 应用可以通过我们的Spring Boot Admin客户端&#xff08;通过HTTP的方式&#xff0…

Vue项目的创建、运行与端口号修改

前言&#xff1a;Vue-cli是Vue官方提供的一个脚手架&#xff0c;用于快速生成一个Vue的项目模板&#xff0c;依赖于NodeJS环境 NodeJS下载&#xff1a;NodeJS安装下载 Vue-cli下载&#xff1a;Vue-cli下载 一.Vue图形化创建项目 1.建立一个文件夹&#xff0c;保存Vue项目 2.在该…

华为P40无法链接adb的解决记录

真的很讨厌华为的设备&#xff0c;很多东西啥设备都能跑得好好的&#xff0c;就华为会出问题&#xff0c;简直就是手机界的IE。 情况&#xff1a;突然无法链接adb到P40&#xff0c;拔插无效&#xff0c;关闭开发人员选项再打开也无效&#xff0c;撤销USB调试授权也无效&#x…

xcode opencv

1、导入报错 Undefined symbols: linker command failed with exit code 1 (use -v to see invocation) 直接添加如下图内容即可

ArkTS-WebView内嵌H5页面

鸿蒙开发使用WebView内嵌H5页面 访问在线网页时需添加网络权限&#xff1a;ohos.permission.INTERNET module.json5文件配置 {"module" : {"requestPermissions":[{"name": "ohos.permission.INTERNET"}]} }踩坑日记 加载网页效果无法…

python-爬虫(可直接使用)

爬虫&#xff08;Web Scraping&#xff09;是指通过编程自动化地获取互联网上的信息的过程。爬虫的目的通常是从网页中抓取数据&#xff0c;进行数据分析、处理或展示。以下是爬虫的基本流程和一些重要的概念&#xff1a; 爬虫基本流程&#xff1a; 确定目标&#xff1a; 确定要…

React 之 airbnb - 项目实战

一、开发前言 1. 规范 2. 创建项目 node -v > 18.0.0 npm -v > 8.6.0 create-react-app star-airbnb 3. 项目基本配置 配置jsconfig.json {"compilerOptions": {"target": "es5","module": "esnext","ba…

如何设置带有密码的excel只读模式?

Excel只读模式大家都不陌生&#xff0c;那大家知道带有密码的只读模式吗&#xff1f;今天给大家分享如何设置带有密码的只读模式。 打开excel文件&#xff0c;将文件进行【另存为】设置&#xff0c;然后停留在保存路径的界面中&#xff0c;我们点击下面的工具 – 常规选项 在常…

postgresql以及postgis安装

一、安装postgresql及postgis 1.下载postgresql https://www.enterprisedb.com/downloads/postgres-postgresql-downloads 我选择的版本为“postgresql-14.8-2-windows-x64.exe”。 2.以管理员模式运行安装程序 安装路径建议不要C盘&#xff0c;可能会由于权限问题导致目录…

【计算机毕业设计】nodejs+vue音乐播放器系统 微信小程序83g3s

本系统的设计与实现共包含12个表:分别是配置文件信息表&#xff0c;音乐列表评论表信息表&#xff0c;音乐论坛信息表&#xff0c;歌手介绍信息表&#xff0c;音乐资讯信息表&#xff0c;收藏表信息表&#xff0c;token表信息表&#xff0c;用户表信息表&#xff0c;音乐类型信…

Elasticsearch:向量搜索 (kNN) 实施指南 - API 版

作者&#xff1a;Jeff Vestal 本指南重点介绍通过 HTTP 或 Python 使用 Elasticsearch API 设置 Elasticsearch 以进行近似 k 最近邻 (kNN) 搜索。 对于主要使用 Kibana 或希望通过 UI 进行测试的用户&#xff0c;请访问使用 Elastic 爬虫的语义搜索入门指南。你也可以参考文章…

最新AIGC创作系统ChatGPT系统源码+DALL-E3文生图+图片上传对话识图/支持OpenAI-GPT全模型+国内AI全模型

一、AI创作系统 SparkAi创作系统是基于ChatGPT进行开发的Ai智能问答系统和Midjourney绘画系统&#xff0c;支持OpenAI-GPT全模型国内AI全模型。本期针对源码系统整体测试下来非常完美&#xff0c;可以说SparkAi是目前国内一款的ChatGPT对接OpenAI软件系统。那么如何搭建部署AI…

Java实现通过经纬度求两个任意地点在球面上的距离

我们在实际开发中会获取对应的经纬度&#xff0c;可以使用ES大数据搜索引擎进行计算对应区域的数据&#xff0c;那我们在如何根据两个经纬度获取对应的球面距离&#xff0c;就是在地球上从一个地点到另一个地点的直线距离 工具类如下: public class GeoUtils {// 地球半径&am…