题目描述
给定一个未排序的整数数组,找出最长连续序列的长度。
要求算法的时间复杂度为 O(n)。题目来源
示例
输入: [100, 4, 200, 1, 3, 2]
输出: 4
解释: 最长连续序列是 [1, 2, 3, 4]。它的长度为 4。
题解及思路
思路1
题目要求时间复杂度为O(n)。大多数情况下,如果不需要限制时间复杂度的暴力法应该可以过,但是有这个要求,多多少少需要用到数据结构。按照题目的意思也就是找到公差为1的最长子数组。这里用到去重的集合Set,首先遍历一次,把所有的点加入到Set集合。然后重新遍历数组,在遍历数组的过程中,朝着一个方向按照公差为1的序列不断在set集合中查找,同时定义计数器保存最大值。这里给出代码,代码中是不断往后查找,往大的数方向查找。
public int longestConsecutive(int[] nums) {
HashSet<Integer> num_set = new HashSet<>();
for (int num : nums) {
num_set.add(num);
}
int res = 0;
for (int num : num_set) {
if (!num_set.contains(num - 1)) { // 保证只往一个方向找 放置重复找浪费时间
int currentNum = num;
int currentStreak = 1;
while (num_set.contains(currentNum + 1)) {
currentNum++;
currentStreak++;
}
res = Math.max(res, currentStreak);
}
}
return res;
}
思路2
采用并查集的方法来做。同样也需要用到set集合,因为不知道传入数组的数据范围,所以采用map结构来定义parent数组,和计数数组。在联合的过程中同样也是判断集合中有没有公差为1的另一个数,有的话就进行联合,联合之后,更新父亲节点的深度。
Map<Integer,Integer> parent;
Map<Integer,Integer> count; // 记录有多少个孩子节点,包括自身
public int longestConsecutive(int[] nums) {
parent = new HashMap<>();
count = new HashMap<>();
Set<Integer> set = new HashSet<>();
for (int num : nums) {
set.add(num);
parent.put(num, num);
count.put(num, 1);
}
int max = 0;
for (int i = 0; i < nums.length; i++) {
int t = nums[i];
if (set.contains(t - 1)) { // 如果包含就进行联合。
union(t - 1,t);
}
max = Math.max(max,count.get(find(t)));
}
return max;
}
private void union(int x, int y) {
int x_root = find(x);
int y_root = find(y);
if (x_root == y_root) {
return;
} else {
parent.put(x_root,y_root);
// 更新深度
count.put(y_root, count.get(x_root) + count.get(y_root));
}
}
private int find(int x){
int x_root = parent.get(x);
if (x_root == x) return x_root;
int x_root_root = find(x_root);
// 提前进行树深度压缩
parent.put(x,x_root_root);
return x_root_root;
}
但是这个方法会比第一个方法慢一些。