LeetCode 128.最長連續序列(Longest Consecutive Sequence)【並查集】【HashMap技巧】

給定一個未排序的整數數組,找出最長連續序列的長度。
要求算法的時間複雜度爲 O(n)。

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

中等難度題吧,不算hard題,需要了解並查集用法

將連續的數字進行合併成一個集合,最後看所有集合中哪個集合數目最多(或者直接邊合併邊記錄最大值)
#include <vector>
#include <algorithm>
#include <unordered_map>
#include <set>
#include <map>
#include <unordered_set>
#include <iostream>
using namespace std;
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;
	}
};

int main()
{
	Solution Solution;
	vector<int> nums{ 100,4,200,1,3,2 };
	cout << Solution.longestConsecutive(nums) << endl;
}


網上另一種解法,使用HashMap進行存 nums[i] 值和其對應時刻下最長連續序列的長度。
通過搜尋當下nums[i]的左右臨邊值是否存在,從而在HashMap中進行修改 當前 子序列的兩邊界的value值(當前子序列的長度),方便後續的nuns[i]值進行搜索左右臨邊值,可以直接用(因爲遇到相同的值,即HashMap中已經存在的,不需要再判斷了,而且也不需要實時更新value值,只是需要更新當前子序列兩端value值即可

class Solution {
public:
    int longestConsecutive(vector<int>& nums) {
        if(nums.empty()) return 0;
        unordered_map<int, int> record;
        int max_count = 0;
        for(int i=0; i<nums.size(); i++)
        {
        	//已經判斷過這個數,則不需要再判斷第二遍
            if(record.find(nums[i]) != record.end()) continue;
            //當前數nums[i]的左右兩邊的數,對應的最長連續序列的個數(有可能沒有左右兩邊的數,沒有的話,個數就是0)
            int left = 0;
            int right = 0;
            if(record.find(nums[i]-1) != record.end())
                left = record[nums[i]-1];
            if(record.find(nums[i]+1) != record.end())
                right = record[nums[i]+1];
            int count = 1+left+right;
            //保存nums[i]在當前時刻的 最大連續序列的個數
            record[nums[i]] = count;
            //更修nums[i] 最遠的 左右兩邊的數的 最大連續序列的個數
            if(left) record[nums[i]-left] = count;
            if(right) record[nums[i]+right] = count;
			
			//實時判斷修改最大值
            if(max_count < count)
                max_count = count;
        }
        return max_count;
    }
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章