题目描述
给定一个未排序的整数数
nums
,找出数字连续的最长序列(不要求序列元素在原数组中连续)的长度。 请你设计并实现时间复杂度O(n)
的算法解决此问题。
解法一:并查集
这道题目可以用并查集来解决。初始状态下数组中的每个元素都是一个独立的集合,然后遍历数组,将当前元素相邻的 元素合并到一个集合,最后返回所有集合中元素个数最多的数量。这里要注意去重。
1#include <vector>
2#include <unordered_map>
3
4class UnionFind {
5public:
6 UnionFind(int num) {
7 for (int i = 0; i < num; ++i) {
8 parent_.push_back(i);
9 size_.push_back(1);
10 }
11 }
12
13 void unite(int p, int q) {
14 int pRoot = find(p);
15 int qRoot = find(q);
16 if (pRoot == qRoot) {
17 return;
18 }
19 parent_[pRoot] = qRoot;
20 size_[qRoot] += size_[pRoot];
21 }
22
23 int find(int p) {
24 if (p != parent_[p]) {
25 parent_[p] = find(parent_[p]);
26 }
27 return parent_[p];
28 }
29
30 int maxConnectedSize() {
31 int ret = 0;
32 for (int i = 0; i < parent_.size(); ++i) {
33 if (parent_[i] == i) {
34 ret = std::max(ret, size_[i]);
35 }
36 }
37 return ret;
38 }
39
40private:
41 std::vector<int> parent_;
42 std::vector<int> size_;
43};
44
45class Solution {
46public:
47 int longestConsecutive(std::vector<int>& nums) {
48
49 // 用于记录元素和下标的对应关系,同时也用来去重
50 std::unordered_map map;
51
52 // 构造一个并查集实例,以下标来表示nums中的一个数字
53 // 初始状态下,每个元素都是独立的集合
54 UnionFind uf(nums.size());
55
56 for (int i = 0; i < nums.size(); ++i) {
57 // 去重
58 if (map.find(nums[i]) != map.end()) {
59 continue;
60 }
61
62 // 将比当前元素小1的元素连接起来
63 if (map.find(nums[i] - 1) != map.end()) {
64 uf.unite(i, map[nums[i] - 1]);
65 }
66
67 // 将比当前元素大1的元素连接起来
68 if (map.find(nums[i] + 1) != map.end()) {
69 uf.unite(i, map[nums[i] + 1]);
70 }
71
72 // 记录元素和下标的对应关系
73 map[nums[i]] = i;
74 }
75
76 // 返回最终所有集合中,元素最多的集合的元素个数
77 return uf.maxConnectedSize();
78 }
79};
评论