Longest Consecutive Sequence 优化强迫症第二弹

题目大意

       给定一组数字,返回最长的连续数字长度

思路

        此题是个很不错的题目,可以不断地压缩复杂度,很能锻炼思维。首先最容易想到的方法就是先对数组排序,然后遍历数组,记录长度后找到最大值(方法一)。这个时间复杂度是O(n*logn),leetcode上使用这种方法是可以水过的(亲测100ms),显然这种方法不符合题目要求的O(n)时间复杂度。

由于方法一的时间主要花费在排序上,那么题目就不允许排序操作,很自然地会想到hash,想到hash不难,难的是如何使用hash去降低时间复杂度,我使用两个hashmap:mp_ele记录(当前数,当前数+1)的映射、mp_visited记录(当前数,当前数是否被访问),这样我遍历数组元素num[i]时,若此数未被访问过,我就反复查找其value值、value的value是否存在.....这样循环下去直到不存在在hash中,记录这个循环查找的长度,然后从中找出最大值(方法二),原本以为这是一个O(n)的方法,因为查找过程中会将查找过的值舍去,但提交结果是TLE,仔细一想,发现这个对于顺序才是O(n)如果是逆序就会上升到O(n^2),实在是太不划算,费空间又费时间。但是一直没有想到任何能够同时照顾+1和-1两个方向的hash方法。

既然hash走不通,就想想别的空间耗费方法,看到leetcode那组TLE数据元素大小最大也才不到1000,因此就想到了一个tricky的方法,找出数组中最大值和最小值,建立一个下标从最小值到最大值的bool数组(对于负数情况,只需要下标加上最小的负数值就行了),然后将出现的值都赋值为true,同时记录长度,返回最大值(方法三)。心想着这下时间复杂度和空间复杂度是O(max(a[i])-min(a[i])),应该可以水过。。。结果。。。只能说leetcode数据质量确实不错,短小精悍,在经历了这样一组数据(Last executed input:[2147483646,-2147483647,0,2,2147483644,-2147483645,2147483645])后。。。%#&*$¥。。。又再次成功地TLE了。

        在连续跪在hash和线性数组上之后,思考了一下线段树的可能(方法四),后来发现线段树虽然时间上应该可以降到(n*logn),但空间消耗过于巨大,而且代码又复杂,时间复杂度也没到O(n)就没有尝试这种方法了。

        实在对此题无力,最后还是参考了一下discussion大神们的方法,发现他们很好地利用了hashmap键和值分别作为边界(两者都有可能是上下界),并且保证只需要在当前数num[i]附近增减1位就能找到之前出现过的最大值和最小值,从而计算出长度。

总结

1、判断map中是否存在数要使用其自带的find函数(除非保证键值映射没有0,这样才能使用if(map[key]))来判断是否存在

2、为保证代码清晰自然,可以多使用几个变量保存一些值,这点消耗是非常值得的,不然会很难分析清楚自己的代码

3、写完代码可以手动跑几个样例来避免一些不必要的错误,此时不能浮躁。

代码(附测试)

#include<iostream>
#include<map>
#include<vector>
using namespace std;

int longestConsecutive(vector<int> &num) 
{
    map<int, int> mp_bound;//记录上边界或者下边界 
    mp_bound.clear();
    int max_len = 1;
    for (int i = 0; i < num.size(); i ++){
        if (mp_bound.find(num[i]) == mp_bound.end()){//这里不要用if(mp_bound[num[i]]) 
           mp_bound[num[i]] = num[i];//由于重复的num[i]对hashmap没有影响,这里mp_bound只需要赋值为自己即可,随后的数据才会对其形成新的更改 
           int low = num[i], high = num[i];
           if (mp_bound.find(num[i]+1) != mp_bound.end())  high =  mp_bound[num[i]+1];
           if (mp_bound.find(num[i]-1) != mp_bound.end())  low = mp_bound[num[i]-1];
           mp_bound[low] = high;//同时更新上下边界,保证num[i]只需要位移一步就能找到边界 
           mp_bound[high] = low;
           max_len = max(max_len, high-low+1);           
        }
    }    
    return max_len;
}
int main()
{
    int n;
    //int test[] = {-4,-1,4,-5,1,-6,9,-6,0,2,2,7,0,9,-3,8,9,-2,-6,5,0,3,4,-2};
    int test[] = {-6,6,-9,-7,0,3,4,-2,2,-1,9,-9,5,-3,6,1,5,-1,-2,9,-9,-4,-6,-5,6,-1,3};
    while (cin >> n){
          vector<int> vc;
          //n = 25;
         for (int i =0 ; i < n; i ++){
             int a;
             cin >> a;
             
             //vc.push_back(test[i]);
             vc.push_back(a);
         }
         cout<<longestConsecutive(vc)<<endl;
    }
	return 0;
}
/*
5
5 4 3 2 1
6
100 4 200 1 3 2
*/


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值