给定一个未排序的整数数组 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
提示:
0 <= nums.length <= 104
-109 <= nums[i] <= 109
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/longest-consecutive-sequence
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
这次开始的思路就是排序后扫描,时间复杂度O(n*log n),注意这里排序后要去重。
进阶的算法需要时间复杂度为O(n)这个我没想出来,看标签说是并查集,才想起来还有这么一个数据结构,扫描的时候把出现的相邻的数字不断合并,带上路径压缩,时间复杂度就是O(n)了。因为数字范围很大,所以需要先映射一下。
官方题解没有给出并查集的解法,用的是hash判断数字是否存在+扫描,扫描的时候枚举的数字n满足,n-1不存在,即找到每个连续段的第一个数字开始扫描,这样保证复杂度是O(n),非常巧妙。
hash判断数字+扫描代码:
class Solution {
public int longestConsecutive(int[] nums) {
int length = nums.length;
if (length <= 1) {
return length;
}
Set<Integer> set = new HashSet<>();
for (int a : nums) {
set.add(a);
}
int answer = 0;
for (int a : nums) {
if (!set.contains(a - 1)) {
int count = 1;
while(set.contains(a + count)) {
++count;
}
if (count > answer) {
answer = count;
}
}
}
return answer;
}
}
并查集代码:
class Solution {
private int[] parent;
private int[] size;
public int longestConsecutive(int[] nums) {
int length = nums.length;
if (length <= 1) {
return length;
}
Map<Integer, Integer> map = new HashMap<>();
int index = 0;
parent = new int[length + 1];
size = new int[length + 1];
for (int i = 0; i < length; ++i) {
int v = map.getOrDefault(nums[i], 0);
if (v == 0) {
map.put(nums[i], ++index);
v = index;
} else {
continue;
}
parent[v] = v;
size[v] = 1;
//查找前一个、后一个元素;
int v1 = map.getOrDefault(nums[i] - 1, 0);
int v2 = map.getOrDefault(nums[i] + 1, 0);
int p1 = 0;
if (v1 > 0) {
p1 = find(v1);
parent[v] = p1;
++size[p1];
}
if (v2 > 0) {
int p2 = find(v2);
if (p1 == 0) {
parent[v] = p2;
++size[p2];
} else {
parent[p2] = p1;
size[p1] += size[p2];
}
}
}
int answer = 0;
for (int i = 1; i <= index; ++i) {
if (size[i] > answer) {
answer = size[i];
}
}
return answer;
}
private int find(int v) {
if (v == parent[v]) {
return v;
} else {
parent[v] = find(parent[v]);
return parent[v];
}
}
}