47.最长连续序列
题目
给定一个未排序的整数数组 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 <= 105
- -109 <= nums[i] <= 109
思路
首先,本题是不能排序的,因为排序的时间复杂度是 O(nlogn),不符合题目 O(n) 的要求。
题解说的比较复杂,不太容易懂,简单来说就是每个数都判断一次这个数是不是连续序列的开头那个数。
怎么判断呢,就是用哈希表查找这个数前面一个数是否存在,即num-1在序列中是否存在。
为了做到 O(n) 的时间复杂度,需要两个关键优化:
- 把 nums 中的数都放入一个哈希集合中,这样可以 O(1) 判断数字是否在 nums 中。
- 存在那这个数肯定不是开头,直接跳过。
- 因此只需要对每个开头的数进行循环,直到这个序列不再连续,因此复杂度是O(n)。
以题解中的序列举例:
[100,4,200,1,3,4,2]
去重后的哈希序列为:
[100,4,200,1,3,2]
按照上面逻辑进行判断:
- 元素100是开头,因为没有99,且以100开头的序列长度为1
- 元素4不是开头,因为有3存在,过
- 元素200是开头,因为没有199,且以200开头的序列长度为1
- 元素1是开头,因为没有0,且以1开头的序列长度为4,因为依次累加,2,3,4都存在。
- 元素3不是开头,因为2存在,过,
- 元素2不是开头,因为1存在,过。
class Solution {
fun longestConsecutive(nums: IntArray): Int {
var result = 0
val hashSet = HashSet<Int>()
for (i in nums) {
hashSet.add(i)
}
for (i in hashSet) {
if (hashSet.contains(i - 1)) {
// 不是开头
continue
}
var len = 1
while (hashSet.contains(i + len)) {
len ++
}
result = maxOf(result, len)
}
return result
}
}
class Solution {
public int longestConsecutive(int[] nums) {
Set<Integer> num_set = new HashSet<Integer>();
for (int num : nums) {
num_set.add(num);
}
int longestStreak = 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 += 1;
currentStreak += 1;
}
longestStreak = Math.max(longestStreak, currentStreak);
}
}
return longestStreak;
}
}
class Solution:
def longestConsecutive(self, nums: List[int]) -> int:
longest = 0
numSet = set(nums)
for num in numSet:
if num -1 not in numSet:
# 这就是开头,可以开始计数
currentNum = num
currentStreak = 1
while currentNum + 1 in numSet:
currentNum += 1
currentStreak += 1
longest = max(longest, currentStreak)
return longest
复杂度分析:
-
时间复杂度:O(n),其中 n 为数组的长度。具体分析已在上面正文中给出。
-
空间复杂度:O(n)。哈希表存储数组中所有的数需要 O(n) 的空间。
- 邮箱 :charon.chui@gmail.com
- Good Luck!