输入一个乱序数列,输出其中连续数列的长度,要求算法复杂度为 O(n)
例如:输入 1,3,2,5,9,190 。那么连续数列就是 1,2,3 。输出:3
起始最简单的方法就是:先把数组排好序,然后查找最长连续数列。但是这样一来算法复杂度是: O(nlogn) + O(n) ,是不符合要求的。
要以算法复杂度为O(n)解决问题可以使用 hash map 。
思路:
我们在人工查找的时候思路是这样的: 从第一个数字看起,看到数字 1 ,就去找 0 和 2,发现没有 0 但是有 2,此时最长序列是 2,然后往下找 3 ,然后往下找 4..... , 如果当前数组的最左边和对右边都没有连续的数字了,那么当前最长数列的值就是: 当前数字左边连续数列长度 + 当前数字右边连续数列长度 + 1。
已给出的数组为例:第一个数值 1 左侧连续数列长度为 0 ,右侧连续数列的值有 2 和 3,长度为 2 ,则连续数列的长度 = 0 + 2 + 1 = 3 .....以此类推可以求出最长连续数列的值 。
1、先把所有数据 (nums数组) 都放进map (numsMap)中,以数值为 key,True为value ,去查找有没有当前数值的下一位的时候不去遍历 nums ,而是去 numsMap 的 allKeys 中查找。
2、遍历 nums ,以 left 记录 i 左侧连续数列长度, right 记录 i 右侧连续数列长度 , leftKey = i - 1 , rightKey = i + 1, 以 leftKey 和 rightKey 为 分别 key 去 numsMap 中查找,如果找到 left += 1 , right += 1 , leftKey -= 1 , rightKey -= 1 将当前键值对从 numsMap 中 pop 出去, 然后继续向下查找,直到 leftKey 和 rightKey 都找不到了 在整个 遍历过程中 maxLength = left + right + 1 。
下面是完成的 python 代码实现:
import sys
for line in sys.stdin:
line = line.strip()
nums = line.split(",")
max_length = 0
# list 中所有的元素作为 map 的key值
numsMap = {}
for i in nums:
i = int(i)
numsMap[i] = True
for i in nums:
i = int(i)
if i not in numsMap.keys():
continue
leftLength = 0
rightLength = 0
leftKey = i - 1
rightKey = i + 1
while leftKey in numsMap.keys():
numsMap.pop(leftKey)
leftKey -= 1
leftLength += 1
while rightKey in numsMap.keys():
numsMap.pop(rightKey)
rightKey += 1
rightLength += 1
max_length = max(max_length, rightLength+leftLength+1)
print (max_length)
还有一种思路就是:numsMap 的key 为 数值, value 为 与当前数值相连的最长数列的长度 。这种思路不做过多讲解了,有兴趣的可以自己研究下。贴出代码:
for i in nums:
i = int(i)
if i in numsMap.keys():
continue
left = 0
right = 0
# i - 1
leftKey = i - 1
# i + i
rightKey = i + 1
# 如果拿到 left 值
if leftKey in numsMap.keys():
left = numsMap[leftKey]
if rightKey in numsMap.keys():
right = numsMap[rightKey]
length = left + right + 1
# 存储到字典
numsMap[i] = length
# 更新与 i 相连的连续序列的最左边和最右边的值
numsMap[i-left] = length
numsMap[i+right] = length
max_length = max(max_length, length)