给定一个未排序的整数数组 nums ,找出数字连续的最长序列(不要求序列元素在原数组中连续)的长度。
请你设计并实现时间复杂度为 O(n)的算法解决此问题。
是什么?
未排序数组,求最长连续子序列
怎么做?
通过hashset
为什么这里需要hashset呢?之前我们用过hashmap,他们有什么区别?(不要喷七七,七七老师没讲哈希,连io流都是七七自学的,虽然博客是写给自己看的,嘿嘿)
功能区别
HashSet
HashSet 是一个不包含重复元素的集合(Set 接口的实现)。
它不允许存储重复的元素,并且不保证元素的顺序。
内部使用 HashMap 来实现,元素作为 HashMap 的键(Key),值是一个默认的 PRESENT 对象。
HashMap
HashMap 是一个键值对(Key-Value)的集合(Map 接口的实现)。
它允许存储唯一的键和对应的值,键不能重复,但值可以重复。
通过键可以快速查找和操作对应的值。
- 数据结构
HashSet HashSet 内部使用 HashMap,它将元素作为键存储,值是一个固定的 Object(通常是一个空对象 new Object())。
HashMap HashMap 使用哈希表实现,存储的是键值对(Entry 对象),通过键的哈希值快速定位存储位置。
- 常用操作
HashSet
添加元素:add(E e)
删除元素:remove(Object o)
判断是否包含元素:contains(Object o)
获取集合大小:size()
HashMap
添加键值对:put(K key, V value)
删除键值对:remove(Object key)
获取值:get(Object key)
判断是否包含键:containsKey(Object key)
获取集合大小:size()
- 线程安全性
HashSet 和 HashMap 都不是线程安全的。如果需要线程安全的实现,可以使用 Collections.synchronizedSet() 或 Collections.synchronizedMap() 来包装。
- 应用场景
HashSet 当需要存储不重复的元素集合时,例如去重操作、集合运算(交集、并集等)。
HashMap 当需要存储键值对,并通过键快速查找和操作值时,例如缓存、字典等场景。
- 性能
HashSet 因为内部使用 HashMap,所以性能与 HashMap 类似,添加、删除和查找操作的时间复杂度为 O(1)。
HashMap 同样基于哈希表,添加、删除和查找操作的时间复杂度为 O(1)。
总结
如果需要存储不重复的元素集合,使用 HashSet。
如果需要存储键值对,并通过键快速查找值,使用 HashMap。
灵宝对他们两个区别有着非常详细的介绍,其实只要记住总结就可以了。
提问:这道题需不需要去重?为什么?
重复元素问题
如果你使用的是 List 或数组等允许重复的结构,那么相同的元素会被多次添加。
在后续处理中(例如查找连续序列、统计唯一元素个数等),重复元素会被多次处理,导致结果错误或效率低下。
- 性能问题
如果不去重,每次处理都需要检查是否已经处理过某个元素,这会导致时间复杂度增加(例如从 O(n) 变成 O(n²))。
例如,在查找最长连续序列时,重复处理相同的数字会导致不必要的计算。
- 逻辑错误
在某些算法中,重复元素会影响逻辑判断。例如:
查找最长连续序列时,重复的数字会导致错误的连续性判断。
统计唯一元素个数时,结果会比实际多。
好了好了,七七已经把这道题的疑问解决了,接下来我们看看代码吧!
import java.util.HashSet;
class Solution {
public int longestConsecutive(int[] nums) {
// 初始化当前数组集合与最大长度
int maxnum = 0;
int current = 0;
// 创建数组集合
HashSet<Integer> set = new HashSet<>();
// 通过遍历数组集合去重
for (int num : nums) {
set.add(num);
}
for (int num : set) {
// 判断是否为第一个数
if (!set.contains(num - 1)) {
int currentNum = num;
current = 1;
// 一直遍历找到当前数组集合的末尾
while (set.contains(currentNum + 1)) {
currentNum++;
current++;
}
maxnum = Math.max(maxnum, current);
}
}
return maxnum;
}
}
完结撒花!!!
