[leetcode] Longest Consecutive Sequence

题目:给定一个无序数组,求最长的连续序列的长度。

例如:给定[100,4,200,1,3,2],则最长的连续序列为[1,2,3,4], 返回4即可。

要求:算法时间复杂度为O(n).

思路一: 看到题目,最直观的想法就是先排序,然后遍历一遍有序数组使用类似动态规划的思想求解最长连续序列。但又要求时间复杂度为O(n),所以就想到了基数排序。基数排序基本上是线性时间复杂度。int型一般为4个字节,可以将int当做无符号整数从低字节到高字节进行基数排序,则相当于有4个关键字,每个关键字(一个字节)取值范围是0~255。由于最高位是符号位(0表示正,1表示负),故排好之后的序列是:从小到大的正数在前,从小到大的负数在后,将负数部分提到正数部分前面,则变为整体有序。具体代码如下:

class Solution {
public:

    void BucketSort(vector<int>& nums){
        int n = nums.size();
        int r = sizeof(int);  // 一般为4个字节
        vector<int> tmp;
        int c[256];
        for(int i=0; i<r; ++i){
            tmp = nums;
            // 计数排序
            memset(c,0,sizeof(c));
            for(int j=0; j<n; ++j){
                int idx = (tmp[j]>>(i*8)) & (0x000000ff);
                ++ c[idx];
            }
            c[255] = n - c[255];
            for(int i = 254; i>=0; --i){
                c[i] = c[i+1] - c[i];
            }
            for(int j=0; j<n; ++j){
                int idx = (tmp[j]>>(i*8)) & (0x000000ff);
                nums[c[idx]++] = tmp[j];
            }
        }
        tmp = nums;
        int k = n;
        for(int i=0; i<n; ++i){
            if(tmp[i] < 0){
                k = i;
                break;
            }
        }
        int j = 0;
        for(int i=k; i<n; ++i){ // 负数部分移至前面
            nums[j++] = tmp[i];
        }
        for(int i=0; i<k; ++i){ // 正数部分置于其后
            nums[j++] = tmp[i];   
        }
    }

    int longestConsecutive(vector<int>& nums) {
        int ret = 0;
        if(nums.empty())   return 0;
        BucketSort(nums);
        ret = 1;
        int tmp = 1;
        for(int i=1; i<nums.size(); ++i){
            if(nums[i] == nums[i-1] + 1){
                ++ tmp;
                ret = max(ret, tmp);
            }else if(nums[i] == nums[i-1]){  // 注意数组中有相同元素
                
            }else{
                tmp = 1;
            }
        }
        return ret;
    }
};

思路二:看了题目的标签是并查集(Union Find),就是说要将连续的元素置于同一分组中。当访问到某个元素e时,就去查看e+1和e-1在不在数组中,然后分别顺次向+1和-1的方向查找,直到找不到下一个相邻的元素为止;同时要在查找的过程中标记数组中已经访问过的元素。由于哈希查找的时间约为O(1),故整体时间复杂度约为O(n)。代码如下:

class Solution {
public:
    // 类似并查集分组:访问到一个元素时,检查其相邻元素在不在
    int longestConsecutive(vector<int>& nums) {
        if(nums.empty())   return 0;
        unordered_map<int,int> map;
        for(int i=0; i<nums.size(); ++i){
            map[nums[i]] = i+1;
        }
        unordered_map<int,int>::iterator it;
        int ret = 1, count = 0;
        for(it = map.begin(); it != map.end(); ++ it){
            if(it->second == 0)   continue;
            ++ count;
            map[it->first] = 0;
            int tmp = it->first;
            while(map.find(--tmp) != map.end()){
                ++ count;
                map[tmp] = 0;
            }
            tmp = it->first;
            while(map.find(++tmp) != map.end()){
                ++ count;
                map[tmp] = 0;
            }
            ret = max(ret, count);
            count = 0;
        }
        return ret;
    }
};



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值