过去会遗忘,现在不会

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

统计

最长连续序列

找出一个数组最长的连续序列(重复的不算),要求复杂度位O(N) 。

示例:

输入:nums = [100,4,200,1,3,2]
输出:4
解释:最长数字连续序列是 
[1, 2, 3, 4]。它的长度为 4

假如不考虑复杂度,直接哈希搜索,对每个数都找一下它能连续的长度,返回最大的那个长度就行。

复制代码
class Solution {
public:
    int longestConsecutive(vector<int>& nums) {
unordered_map<int,int> hashtb;
if(nums.size()<2) return nums.size();

for(int i=0;i<nums.size();i++)
{
    if(hashtb.find(nums[i])!=hashtb.end()) continue;
    else hashtb.emplace(nums[i],1);
}

if(hashtb.size()<2) return hashtb.size();

int length=1;
int max=1;
unordered_map<int,int>::iterator it;
unordered_map<int,int>::iterator it1;
unordered_map<int,int>::iterator it2;
for(it=hashtb.begin();it!=hashtb.end();it++)
{
    it1=it;

    while(hashtb.find(it1->first+1)!=hashtb.end())
    {
        it2=hashtb.find(it1->first+1);
        it1=it2;
        length++;
    }
    max=max>length?max:length;
    length=1;

}
return max;
    }
};
复制代码

显而易见的超时,因为时间复杂度是O(N2)。

当然只是练习下哈希表,直接sort排序不比这快?问题是sort复杂度是O(Nlogn),也不满足条件啊。

所以怎么达到O(N)的复杂度?就是每个数只遍历一遍就找出最长的连续数列。

那就加个判定条件,让遍历过的数不再重复遍历。

具体怎么加呢?因为我们必定从哈希表的开头开始遍历,假设为x,找x的前驱x-1,一直找到最小的那个,之后在找他的后驱x+1,一直找到最大的那个,每找到一个就在哈希表里删除这个数,长度+1,最后删除x本身。

继续从开头遍历,直到哈希表删光。

复制代码

class Solution {
public:
    int longestConsecutive(vector<int>& nums) {
unordered_map<int,int> hashtb;
if(nums.size()<2) return nums.size();

for(int i=0;i<nums.size();i++)
{
    if(hashtb.find(nums[i])!=hashtb.end()) continue;
    else hashtb.emplace(nums[i],1);
}


int length1=0;
int length2=0;
int length=0;
int max=0;
unordered_map<int,int>::iterator it;
unordered_map<int,int>::iterator it1;
unordered_map<int,int>::iterator it2;


while(!hashtb.empty())
{
    it=hashtb.begin();
 
        it1=it;
    while(hashtb.find(it1->first-1)!=hashtb.end())
    {
        length1++;
        it1=hashtb.find(it1->first-1);
    }

        it2=it;
    while(hashtb.find(it2->first+1)!=hashtb.end())
    {
        cout<<it2->first<<",";
        length2++;
        it2=hashtb.find(it2->first+1);
    }
length=length1+length2+1;
max=max>length?max:length;

/*
if(length1=0){}
else{
for(int i=0;i<length1;i++)
{
    hashtb.erase(it1);
    it1=hashtb.find(it1->first+i+1);
}
}
if(length2=0){}
else{
for(int j=0;j<length2;j++)
{
    hashtb.erase(it2);
    it2=hashtb.find(it2->first-j-1);
}
}
*/
hashtb.erase(it);
length1=0;length2=0;length=0;
}
return max;
}

    
};
 
复制代码

两种erase删除的方式都会超时... 看来利用erase是不行了,毕竟erase()函数本身就有O(N)的时间复杂度

不过有了另一种思路,

上面我们用的是数组的begin()作为基准数,找他的左右连续数,形成一个有序数列。

假如直接找一个有序数列的第一位呢?对于{2,3,5,1,4,7,6,10,11}直接找1,然后形成一个{1,2,3,4,5,6,7}这样的数列,长度为7;之后找到10,形成{10,11}这样的数列,长度为2。

代码如下:

复制代码
class Solution {
public:
    int longestConsecutive(vector<int>& nums) {
if(nums.size()<2) return nums.size();
unordered_map<int,int> hashtb;
for(int i=0;i<nums.size();i++)
{
    hashtb.emplace(nums[i],1);
}
if(hashtb.size()<2) return hashtb.size();

int max=1;
int length=1;
for(auto it=hashtb.begin();it!=hashtb.end();it++)
{
 if(hashtb.find(it->first-1)!=hashtb.end()) continue;//判断是不是序列起点 不是就下一次循环
 else
 {   auto itend=it;
    while(hashtb.find(itend->first+1)!=hashtb.end())//找到序列的终点和长度
    {
    length++;
    itend=hashtb.find(itend->first+1);
    }
    max=max>length?max:length;
    length=1;
 }
}

return max;
    }
};
复制代码

好像时间没超过,似乎可行。但时间似乎还是有点长?

PS:为什么定义了<int,int>类型的哈希表? 因为之前想着如果重复的数也算长度的话,在构建哈希表的时候,value就会存储key出现的次数,这样的话,总长度只要加上value就可以了。

 

还有啥办法呢??我记得unordered_map是无序的,而map和set是有序的。那么我用map或者set找到一个最长的连续序列不也是可以吗?试一下。

复制代码
class Solution {
public:
    int longestConsecutive(vector<int>& nums) {
        if(nums.size()<1) return nums.size();

set<int> set;
for(int i=0;i<nums.size();i++)
{
    set.insert(nums[i]);
}

int max=1;
int length=1;
auto it=set.begin();

while(it!=set.end())
{
    
   if(set.count(*it+1))
   { 
       while(set.count(*it+1))
        {
            length++;
            it++;
        }
   }
   else {it++;}

    max=max>length?max:length;
    length=1;
}


return max;
    }
};
复制代码

好像时间占用和空间占用更大了????时间复杂度O(nlogn)也不满足题意.......

话说那些更快的算法怎么就直接sort了??不过动态规划是好像有点厉害。

 

posted on   WhatAnyWay  阅读(95)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· 终于写完轮子一部分:tcp代理 了,记录一下
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
点击右上角即可分享
微信分享提示