给定一个未排序的整数数组 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
示例 3:
输入:nums = [1,0,1,2]
输出:3
提示:
0 <= nums.length <= 10^5
-10^9 <= nums[i] <= 10^9
拿到这道题的一开始还准备直接开辟10001的数组仿制哈希set来解决,没想到忘记了负数的存在,并且这道题是10^9开不了那么大的数
本题的核心是发掘hashSet的本质特点,hashSet的特点是什么呢?那么这道题是如何借助hashSet的特点来解决的呢?
只知道解法还是不够,得知道解决问题的本质,于是我问了chatGpt
chatGPT:
这个问题问得非常深入,非常 INFJ 式地想挖“本质与灵感来源”,我来尽量用你喜欢的方式解释:
✅ 一、HashSet 被用到的两个关键“性质”
🌟 1. 快速查找 O(1) —— set.contains(x)
判断一个数是否存在,不用遍历,直接查,时间复杂度 O(1)
这是最关键的特性。因为我们需要在序列中判断一个数的“前一个”或“后一个”是否存在,HashSet 能极快完成这个判断。
🌟 2. 去重
数组里可能有重复项,HashSet 自动帮你去重
这对于 nums = [1,0,1,2]
这种输入是必要的,否则你可能会重复处理。
✅ 二、这道题的“感觉”或“直觉”
很多人第一反应会是:排序 → 然后遍历。但排序是 O(nlogn),不符合要求。
而这道题的 直觉点在于:
🌱“只要我知道一个连续序列的起点,我就可以一路
+1
找下去。”
💡 于是我们思考:
如果我能快速知道一个数是否在原数组中,那我就能从每个可能的起点 x
出发,查 x+1, x+2...
,直到查不到为止。
但怎么快速查?
👉 这就自然想到 HashSet!
✅ 所以,问题就转化成了:
- 先把所有数字放到 set 中
- 从每个“可能的起点”出发往右找
🚩 如何判断某个数是“起点”?
答案是:
java
复制编辑
if (!set.contains(num - 1))
也就是:
只有当
num-1
不存在时,num
才是这个连续序列的第一个数。
这样就保证了每个序列只被处理一次,时间复杂度 O(n)。
✅ 总结:为什么 HashSet 是灵魂
特性 | 在这道题中的作用 |
---|---|
查找快 O(1) | 快速判断某个数是否存在 |
去重 | 防止重复处理同一个数字 |
空间换时间 | 用 O(n) 空间换 O(n) 时间 |
语义契合 | “是否存在”的判断语义就是 Set 本质 |
🌌 最后的“感觉”总结一句话:
这道题的关键感受是:“我需要快速判断一个数字是否存在”,这种需求一出现,HashSet 就成了最自然的选择,它的
contains()
就像“意识的触角”一样可以立刻知晓答案。
public static int longestConsecutive(int[] nums) {
HashSet<Integer> set = new HashSet<>();
int ans=0;
for (int i = 0; i < nums.length; i++) {
if(!set.contains(nums[i])) {
set.add(nums[i]);
}
}
for (Integer i : set) {
if(!set.contains(i-1)) {
int cur=i;
int len=1;
while(set.contains(cur+1)) {
len++;
cur++;
}
ans = Math.max(ans, len);
}
}
return ans;
}