给定一个未排序的整数数组,找出最长连续序列的长度。
要求算法的时间复杂度为 O(n)。
示例:
输入: [100, 4, 200, 1, 3, 2]
输出: 4
解释: 最长连续序列是 [1, 2, 3, 4]。它的长度为 4。
思路:
难点在于算法复杂度要求。
复杂度嘛。一点一点降下来
1. 最好想的暴力枚举
将数组的每个元素作为序列起始(
O
(
n
)
O(n)
O(n)),
逐个枚举下一个元素
O
(
n
)
O(n)
O(n),
检查下一个元素在不在数组中
O
(
n
)
O(n)
O(n)
2. 数组排序后一次遍历( O ( n l o g n ) O(nlogn) O(nlogn))
(1)数组排序
(2)类似滑动窗(但窗口大小只是窗口内不同元素的个数):
左端起始点初始化为数组的第0个元素
从第1号元素开始遍历:
如果遍历元素等于前一个元素:
- 那么他不能让序列边长,也不能在这里截断!!!
- 所以continue就完事了
如果遍历元素不等于前一个元素:
- 那看看他是不是前一个元素+1:
+ 是的话:当前序列长度+1
+ 不是的话:更新最长序列长度,更新当前序列长度为1(或者更新左端起点为当前遍历元素,即连续序列重新开始)
总之一次排序+一次遍历
3. HASH检查,空间换时间
暴力方法会超时的主要原因在于,枚举是查找数组的需要顺序查找太费时间了。
但是如果不是查找数组而是查找hash表,复杂度就成了
O
(
1
)
O(1)
O(1)
枚举的起始点元素也在HASH表中找,没有起始点遍历,复杂度也是
O
(
1
)
O(1)
O(1)
那么复杂度就只有确定每个序列起始点后,枚举的
O
(
n
)
O(n)
O(n)了
- python中HASH的实现
- 需要计数之类的可以用dict
- 不需要计数其实可以用set !!! 神器啊。查找set的复杂度是O(1)惊不惊喜意不意外,这才是他跟list本质的不同。
三个思路代码如下:
class Solution:
# O(n^3) 超时暴力枚举
def longestConsecutive(self,nums):
if len(nums) ==0:
return 0
longest = 0
for item in nums:
count = 1
start = item+1
while start in nums:
start+=1
count+=1
if longest<count:
longest = count
return longest
# O(nlogn)
def longestConsecutive2(self, nums):
if len(nums) == 0:
return 0
# O(nlogn)
nums.sort()
# 滑动窗检查O(n)
longest = 1
length = 1
#left = 0
#res =[] #用来保存最长结果,如果需要返回的话
for scanner in range(1,len(nums)):
#current_res = [nums[left]]
# 当前扫描数字不等于前一个数,检查他是否可以加入连续序列
if nums[scanner]!=nums[scanner-1]:
if nums[scanner] == nums[scanner-1]+1:
length+=1
#current_res.append(nums[scanner])
else:
longest = max(length,longest)
length = 1
# if longets == length:
# res = current_res
#left = scanner
# 相等的话不影响序列长度
else:
continue
return max(longest,length)
# O(n):
# 暴力方法改为借助哈希表表,空间换时间:
# 不去不断搜索当前数字+1在不在数组中。
# 遍历数组过程中,存hash表。之后去搜索当前数-1在不在hash表。复杂度O(1)
def longestConsecutive3(self, nums):
longest = 0
# 存成HASH
num_set = set(nums)
for start in num_set:
if start-1 not in num_set:
# start为起始左端
current = start+1
while current in num_set:
current+=1 # current+1
longest = max(longest,current-start)
return longest
# dict版: 多费点内存
def longestConsecutive4(self, nums):
num_dict = {}
for item in nums:
if item not in num_dict.keys():
num_dict[item] = 1
else:
continue
longest = 0
for start in list(num_dict.keys()):
if start-1 not in num_dict.keys():
current = start+1
while current in num_dict.keys():
current += 1
longest = max(current-start, longest)
return longest