给定一个未排序的整数数组 nums ,找出数字连续的最长序列(不要求序列元素在原数组中连续)的长度。
请你设计并实现时间复杂度为 O(n) 的算法解决此问题。
示例 1:
输入:nums = [100,4,200,1,3,2]
输出:4
解释:最长数字连续序列是 [1, 2, 3, 4]。它的长度为 4。
示例 2:
输入:nums = [0,3,7,2,5,8,4,6,0,1]
输出:9
解题思路
题目要求实现时间复杂度为 O(n),所以只能对数组遍历一次。
设ind数组,存储nums数组的下标,ind的下标为nums的值,那么我们可以通过并查集,将nums数组的下标连通。
例1中nums数组为[100, 4, 200, 1, 3, 2]
nums: [100, 4, 200, 1, 3, 2]
0, 1, 2, 3, 4, 5
ind: [, 3, 5, 4, 1,..., 0,..., 2]
1 2 3 4 100 200
通过转换我么可以得到nums数组中连续的序列的下标 3,5,4,1。
那么我们将获取最长序列的值转化成获取最长序列的下标的方法,然后通过并查集来获取最长的连续序列的数量。
代码
class UnionSet {
constructor(n) {
this.parent = new Array(n + 1).fill(0).map((v, index) => index)
this.rank = new Array(n + 1).fill(1)
this.count = n
}
getCount() {
return this.count
}
connected(a, b) {
return this.find(a) == this.find(b)
}
find(x) {
if (this.parent[x] != x) {
this.parent[x] = this.find(this.parent[x])
}
return this.parent[x]
}
merge(a, b) {
let ra = this.find(a), rb = this.find(b)
if (ra == rb) return
if (this.rank[ra] < this.rank[rb]) {
this.parent[ra] = rb
this.rank[rb] += this.rank[ra]
} else {
this.parent[rb] = ra
this.rank[ra] += this.rank[rb]
}
this.count--
}
}
var longestConsecutive = function(nums) {
if (!nums.length) return 0
// 存储数组下标
let ind = new Array()
let u = new UnionSet(nums.length)
for ([i, num] of nums.entries()) {
// 消除重复值
if (ind[num] != ind[ind.length]) continue;
// 如果当前数的前一个数有值
if (ind[num - 1] !== undefined) {
// 合并的是数组下标
u.merge(i, ind[num - 1])
}
// 如果当前数的后一个数有值
if (ind[num + 1] !== undefined) {
u.merge(i, ind[num + 1])
}
ind[num] = i // nums下标
}
let ans = 0
for (let i = 0; i < nums.length; i++) {
// 如果当前下标是树的根节点,且树节点长度大于ans
if (u.find(i) == i && u.rank[i] > ans) ans = u.rank[i]
}
return ans
};