1. 程式人生 > >【LeetCode】128. 最長連續序列 結題報告 (C++)

【LeetCode】128. 最長連續序列 結題報告 (C++)

原題地址:https://leetcode-cn.com/problems/longest-consecutive-sequence/description/

題目描述:

給定一個未排序的整數陣列,找出最長連續序列的長度。

要求演算法的時間複雜度為 O(n)。

示例:

輸入: [100, 4, 200, 1, 3, 2]
輸出: 4
解釋: 最長連續序列是 [1, 2, 3, 4]。它的長度為 4。

 

解題方案:

本題的型別是並查集,從來沒有做過的題型。。學習學習!

初始思路是對陣列進行排序,再查詢最大的連續序列。因為題目要求時間複雜度為O(N),這種方式不可用。

將連續的數字合併為一個數組,最後比較這些陣列,看哪個陣列中的元素最多。。

並查集還是很妙的,其中的相關資料:http://www.cnblogs.com/horizonice/p/3658176.html

百度百科含有列題以及C++程式碼:https://baike.baidu.com/item/並查集/9388442?fr=aladdin#6_2

並查集一般包含建立函式,查詢函式,合併函式。

本程式碼設計很精妙,使用了並查集模組,在模組裡直接定義了並查集的陣列,以及查詢函式和合並函式。

class Solution {
//並查集模板(已優化)
    struct DisJointSet
    {
        vector<int> _id;//元素
        vector<int> _size;//集合內的元素個數
        int max_size;//最大集合的元素個數【額外需要用到的引數】
        int _count;//集合總個數
        DisJointSet(int Num)
        {
            for (int i = 0; i < Num; i++)
            {
                _id.emplace_back(i);
                _size.emplace_back(1);
            }
            _count = Num;
            max_size = 1;
        }
        //查詢
        int find_(int p)
        {
            while (p != _id[p])
            {
                _id[p] = _id[_id[p]];
                p = _id[p];
            }
            return p;
        }
        //合併
        void _union(int p, int q) {
            int i = find_(p);
            int j = find_(q);
            if (i == j)return;
            if (_size[i] > _size[j])
            {
                _id[j] = i;
                _size[i] += _size[j];
                max_size = max(max_size, _size[i]);
            }
            else
            {
                _id[i] = j;
                _size[j] += _size[i];
                max_size = max(max_size, _size[j]);
            }
            _count--;
        }
    };
public:
    int longestConsecutive(vector<int>& nums) {
        if (nums.size() == 0)   return 0;
        DisJointSet disJointSet(nums.size());
        unordered_set<int> nums_set;    //記錄是否有查複數字 或者 是否已經有數字的前後的數
        unordered_map<int, int> nums_disJointSetID_map; //<數字,ID> 與並查集ID一一對應,不需改動模板引數
        for (int i = 0; i < nums.size(); i++)
        {
            if (nums_set.find(nums[i]) != nums_set.end())   continue;   //存在重複數字
            nums_set.insert(nums[i]);
            nums_disJointSetID_map[nums[i]] = i;
            if(nums_set.find(nums[i] - 1) != nums_set.end())    //是否有前一個數
            {
                disJointSet._union(nums_disJointSetID_map[nums[i]], nums_disJointSetID_map[nums[i] - 1]);
            }
            if(nums_set.find(nums[i] + 1) != nums_set.end())    //是否有後一個數
            {
                disJointSet._union(nums_disJointSetID_map[nums[i]], nums_disJointSetID_map[nums[i] + 1]);
            }
        }
        return disJointSet.max_size;
    }
};