剑指 Offer II 119. 最长连续序列
给定一个未排序的整数数组 nums ,找出数字连续的最长序列(不要求序列元素在原数组中连续)的长度。
示例 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
进阶:可以设计并实现时间复杂度为 O(n) 的解决方案吗?
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/WhsWhI
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
分析
方法一:图搜索
把相邻的节点构成的图看作一个岛屿,问题变为求岛屿的最大面积,用一个哈希表存储所有节点,对于每个节点用 bfs 查找其所有邻接点,记录所有相连的节点数目,同时删除哈希表中使用过的节点,因为要删除哈希表的节点,所以使用迭代器进行遍历,遍历所有哈希表中的节点找到最大的岛屿。
方法二:并查集
(用并查集没有直接图搜索快)
并查集要对找到的邻接点用 union 连接,每次连接的节点都是之前的子集,有各自的大小,需要动态保存子集大小的和,考虑使用哈希表 counts 来保存节点和其所在岛屿的大小,用哈希表 fathers 存储所有节点和其根节点,fathers 也可以用哈希表数组,但是范围太大,所以这里使用哈希表,初始化所有哈希表,counts 的 key 保存所有节点,value 保存岛屿大小起始为 1,fathers 的 key 保存所有节点,value 保存根节点起始为 key 的值。接下来进行节点的连接,findFather 和 unoin 的代码跟之前非常类似,只是参数换成了哈希表。最后遍历 counts 找出岛屿的最大面积。
题解(Java)
方法一:图搜索
class Solution {
public int longestConsecutive(int[] nums) {
Set<Integer> set = new HashSet<>();
for (int num : nums) {
set.add(num);
}
int longest = 0;
while (!set.isEmpty()) {
Iterator<Integer> it = set.iterator();
longest = Math.max(longest, bfs(set, it.next()));
}
return longest;
}
private int bfs(Set<Integer> set, int num) {
Queue<Integer> q = new LinkedList<>();
q.offer(num);
set.remove(num);
int length = 1;
while (!q.isEmpty()) {
int i = q.poll();
int[] neighbors = new int[]{i - 1, i + 1};
for (int neighbor : neighbors) {
if (set.contains(neighbor)) {
q.offer(neighbor);
set.remove(neighbor);
length++;
}
}
}
return length;
}
}
方法二:并查集
class Solution {
public int longestConsecutive(int[] nums) {
Map<Integer, Integer> fathers = new HashMap<>();
Map<Integer, Integer> counts = new HashMap<>();
for (int num : nums) {
fathers.put(num, num);
counts.put(num, 1);
}
for (int num : nums) {
if (fathers.containsKey(num + 1)) {
union(fathers, counts, num, num + 1);
}
if (fathers.containsKey(num - 1)) {
union(fathers, counts, num, num - 1);
}
}
int longest = 0;
for (int length : counts.values()) {
longest = Math.max(longest, length);
}
return longest;
}
private int findFather(Map<Integer, Integer> fathers, int i) {
if (fathers.get(i) != i) {
fathers.put(i, findFather(fathers, fathers.get(i)));
}
return fathers.get(i);
}
private void union(Map<Integer, Integer> fathers, Map<Integer, Integer> counts, int i, int j) {
int fatherOfI = findFather(fathers, i);
int fatherOfJ = findFather(fathers, j);
if (fatherOfI != fatherOfJ) {
fathers.put(fatherOfI, fatherOfJ);
int countOfI = counts.get(fatherOfI);
int countOfJ = counts.get(fatherOfJ);
counts.put(fatherOfJ, countOfI + countOfJ);
}
}
}