首页 > 其他分享 >leetcode128. 最长连续序列【三种方法; 并查集; hashtable】

leetcode128. 最长连续序列【三种方法; 并查集; hashtable】

时间:2024-04-02 22:01:37浏览次数:29  
标签:nlogn nums int 查集 num hashtable ans leetcode128 root

文章目录

1 O ( n l o g n ) O(nlogn) O(nlogn)解法:排序与遍历

如果不考虑题干要求的时间复杂度 O ( n ) O(n) O(n),那么排序+一次遍历以 O ( n l o g n ) O(nlogn) O(nlogn)的解法就可以过。

还是写一下 O ( n l o g n ) O(nlogn) O(nlogn)的解法,原因在最后说。

class Solution {
public:
    int longestConsecutive(vector<int>& nums) {
        if (nums.size() == 0)
            return 0;

        sort(nums.begin(), nums.end());

        int ans = 1, curr = 1;
        for (int i = 1; i < nums.size(); i++) {
            if (nums[i] - nums[i - 1] == 1)
                curr++;
            else if (nums[i] == nums[i - 1]) {
            } else {
                ans = max(ans, curr);
                curr = 1;
            }
        }
        ans = max(ans, curr);
        return ans;
    }
};

在这里插入图片描述
真快。那么 O ( n ) O(n) O(n)的解法会更快吗?

2 O ( n ) O(n) O(n)解法:并查集

小记:unorder_map

我一开始实在想不出 O ( n ) O(n) O(n),遂看了一眼此题标签,“哈希表”。我看到哈希表便想到map,而map单次操作的复杂度是logn……注意这种条件反射是错误的。下面才是正确的:

unorder_map的本质是hashtable,插入/查找的时间复杂度可视为 O ( 1 ) O(1) O(1).
而map的本质就是红黑树,插入/查找的时间复杂度为 O ( l o g n ) O(logn) O(logn).

思路

并查集。把已经能串在一串的元素看作一个集合。每个集合中最小的那个数作为根。遍历每个元素,每新增一个元素n,就把n-1所在的那个集合(如果n-1之前出现过)和n+1所在的那个集合(如果n+1之前出现过)以及n合并。hashtable的作用是用O(1)的代价判断n-1和n+1之前是否存在过,以及得到这两个数在nums中的下标。

Q:一个数会不会同时存在与两个集合中?
A:那么这两个集合一定可以合并

class Solution {
    unordered_map<int, int> pos;
    int root[100010]; // 规定小数为根,根的root值代表该集合的秩(负数以示区分)
    int findrt(int ind) // 找出下标为ind的这个数的根
    {
        if (root[ind] < 0)
            return ind;
        return root[ind] = findrt(root[ind]);
    }
    
public:
    int longestConsecutive(vector<int>& nums) {
        memset(root, -1, sizeof(root));
        int ans = 0;
        for (int i = 0; i < nums.size(); i++) {
            if (pos.count(nums[i]) > 0)
                continue;
            pos[nums[i]] = i;

            if (pos.count(nums[i] - 1) > 0) {
                // 把nums[i]连到根上
                int rt_index = findrt(pos[nums[i] - 1]);
                root[rt_index]--; // 秩加1
                root[i] = rt_index;
            }
            if (pos.count(nums[i] + 1) > 0) {
                // 此时nums[i]+1一定是根(因为nums[i]第一次出现)
                // 把nums[i]+1连到nums[i]的根上
                int rt_index = findrt(i);
                root[rt_index] += root[pos[nums[i] + 1]];
                root[pos[nums[i] + 1]] = rt_index;
            }
            ans = max(ans, -root[findrt(i)]);
        }

        return ans;
    }
};

在这里插入图片描述
这个执行用时实在是尴尬,但是我也想不出优化办法了。方法倒是实实在在的 O ( n ) O(n) O(n),这个怎么解释呢,测试样例太弱了……?

3 有些差的官解:哈希

官解是这样想的:外层循环遍历每一个元素,对于每一个元素n,我不停的查找n+1、n+2……这一串是否在数组中(事先用unordered_set存下所有的数),记下最长的串长,即为答案。

评论区也有人说了最差情况,就是倒序的串。这样最差时间复杂度就是O(n*n),还没第一种方法nlogn强了,所以我说这个官解有些差劲。

class Solution {
public:
    int longestConsecutive(vector<int>& nums) {
        unordered_set<int> num_set;
        for (const int& num : nums) {
            num_set.insert(num);
        }

        int longestStreak = 0;

        for (const int& num : num_set) {
            if (!num_set.count(num - 1)) {
                int currentNum = num;
                int currentStreak = 1;

                while (num_set.count(currentNum + 1)) {
                    currentNum += 1;
                    currentStreak += 1;
                }

                longestStreak = max(longestStreak, currentStreak);
            }
        }

        return longestStreak;           
    }
};

在这里插入图片描述

结语

  1. 本题生动形象的解释了 O ( n l o g n ) O(nlogn) O(nlogn)的运行速度真的不见得比 O ( n ) O(n) O(n)慢。
  2. 但是本题我认为最好的方法是并查集。

标签:nlogn,nums,int,查集,num,hashtable,ans,leetcode128,root
From: https://blog.csdn.net/weixin_45339670/article/details/137243811

相关文章

  • 蓝桥杯T5合根植物——并查集模板题
    5.合根植物-蓝桥云课(lanqiao.cn) #include<bits/stdc++.h>usingnamespacestd;intm,n,pre[1000000];set<int>s;intfind(intx){if(pre[x]==x)returnx;returnfind(pre[x]);}intmain(){//请在此输入您的代码cin>>m>>......
  • 并查集模板
    目录并查集的存储结构并查集查询路径压缩并查集合并合并优化--启发式优化合并优化--按秩合并可撤销并查集算法原理重要操作实现并查集是一种巧妙优雅的数据结构,主要用于解决元素分组和不相交集合的合并和查询问题。并查集是大量的树(单个节点也算是树)经过合并生成一......
  • 逆序并查集
    以L2-013红色警报为例原题链接https://pintia.cn/problem-sets/994805046380707840/exam/problems/994805063963230208?type=7&page=1下面贴上代码#include<iostream>usingnamespacestd;constintN=510;intp[N],g[N][N];intfind(intx){if(x!=p......
  • 【LeetCode】LeetCode 547. 省份数量(Java版 什么是并查集)
      ......
  • 【洛谷 P8654】[蓝桥杯 2017 国 C] 合根植物 题解(并查集)
    [蓝桥杯2017国C]合根植物题目描述w星球的一个种植园,被分成m×nm\timesnm×n个小格子(东西方向......
  • 为什么并查集可以用来判环
    本篇适合了解并查集基本运行原理的人并查集(FindUnion)Find的意思就是查找某个元素属于哪个集合集合的标志用祖先来表示如果两个元素的祖先一样那么这两个元素属于一个集合Union的意思是合并两个元素,让这两个元素处于同一祖先下并查集用来判环的原理就是如果两个元素处于同......
  • 十五 528. 奶酪 (并查集)
    528.奶酪(并查集)思路:大体就是并查集的模板,空洞数组从1到n,增加0作为下表面,n+1作为上表面,遍历所有空洞,若与上下表面相切或是相交就将ijoin到0或n+1,然后再比较任意两个空洞,两者相切或是相交就join起来,最后判断0与n+1是否相连。importjava.util.*;publicclassMain{......
  • 并查集专题(附并查集模板)P3367 【模板】并查集 P1656 炸铁路
    并查集模板f数组要初始化autofind(autox){if(f[x]==x)returnx;elsereturnf[x]=find(f[x])路径压缩,同一条路上都归到一个点上}voidunionset(autoa,autob){f[find(a)]=find(b);auto会自动适配数据类型} P3367【模板】并查集题目描述如题......
  • 并查集(反集)进阶 P1892 [BOI2003] 团伙
    现在有 n 个人,他们之间有两种关系:朋友和敌人。我们知道:一个人的朋友的朋友是朋友一个人的敌人的敌人是朋友现在要对这些人进行组团。两个人在一个团体内当且仅当这两个人是朋友。请求出这些人中最多可能有的团体数。输入格式第一行输入一个整数 n 代表人数。第二行......
  • 蓝桥杯算法集训 - Week 4:BFS、并查集、Flood Fill、哈希、单调栈/队列
    蓝桥杯算法集训-Week4本系列随笔用于整理AcWing题单——《蓝桥杯集训·每日一题2024》的系列题型及其对应的算法模板。一、BFSBFS算法复习参考:BFS(Java)广度优先搜索简单介绍、模板、案例(一)Ⅰ、代码模板staticvoidbfs(Troot){//双端队列,用来存储元素D......