LeetCode128. 最长连续序列
LeetCode128. 最长连续序列
- 1. 题目链接
- 2. 问题分析
- 3. 解法一:排序法(虽然不符合要求但很直观)
- 4. 解法二:哈希集合法(符合 O(n) 要求)
1. 题目链接
LeetCode128. 最长连续序列
2. 问题分析
这道题要求找到最长的连续数字序列,这个序列在原数组中不要求元素位置连续,只要数值连续即可。初看之下,似乎很简单——只需要排序后遍历一遍就能找到答案。但题目要求时间复杂度为 O(n),这就排除了基于排序的解法(排序通常为 O(n log n))。
我们需要一种更巧妙的方法,能够在 O(1) 时间内判断某个数字是否存在,这就是哈希表大显身手的地方。
3. 解法一:排序法(虽然不符合要求但很直观)
先来看看最直观的解法,虽然它不符合题目要求,但能帮助我们理解问题:
public int longestConsecutive(int[] nums) {if (nums.length == 0) return 0;// 先排序 - O(n log n)Arrays.sort(nums);int maxLength = 1;int currentLength = 1;for (int i = 1; i < nums.length; i++) {// 跳过重复元素if (nums[i] == nums[i-1]) continue;// 判断是否连续if (nums[i] == nums[i-1] + 1) {currentLength++;maxLength = Math.max(maxLength, currentLength);} else {currentLength = 1;}}return maxLength;
}
这种解法的时间复杂度是 O(n log n),空间复杂度是 O(1)(如果不考虑排序的空间开销)。
4. 解法二:哈希集合法(符合 O(n) 要求)
核心思路:
- 使用哈希集合存储所有数字,实现 O(1) 时间的查找
- 对于每个数字 x,如果 x-1 不存在,说明 x 可能是一个连续序列的起点
- 从这些起点开始,不断查找下一个数字,直到连续性破坏
- 记录过程中找到的最长序列
为什么可以跳过某些数字?
如果一个数字 x 的前驱 x-1 存在,那么 x 肯定不是某个连续序列的起点,从 x 开始找肯定不会得到最长序列,所以直接跳过。
算法步骤
- 创建哈希集合,存入所有数字
- 遍历数组中的每个数字 x:
- 如果 x-1 不在集合中(说明是起点)
- 从 x 开始,尝试找 x+1, x+2, … 直到找不到为止
- 更新最长序列的长度
- 返回最长长度
public int longestConsecutive(int[] nums) {// 创建哈希集合,存入所有数字Set<Integer> set = new HashSet<>();for (int num : nums) {set.add(num);}int maxLength = 0;// 遍历每个数字for (int num : nums) {// 如果num-1存在,说明num不是序列的起点,跳过if (!set.contains(num - 1)) {int currentNum = num;int currentLength = 1;// 不断查找下一个数字while (set.contains(currentNum + 1)) {currentNum++;currentLength++;}maxLength = Math.max(maxLength, currentLength);}}return maxLength;
}
时间复杂度分析
- 构建哈希集合:O(n)
- 外层循环:O(n)
- 内层循环:每个数字最多进入内层循环一次(因为只有起点才会进入内层)
- 总时间复杂度:O(n),符合要求
