给定一个未排序的整数数组,找出最长连续序列的长度。
要求算法的时间复杂度为 O(n)。
示例:
输入: [100, 4, 200, 1, 3, 2]
输出: 4
解释: 最长连续序列是 [1, 2, 3, 4]。它的长度为 4。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/longest-consecutive-sequence
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
首先最开始想到的是暴力法,n^3,肯定通不过
然后是排序,最少的也要nlogn,也不能通过
最后是看解答才知道的
关键在于在集合set中找数是O(1)时间
把所有的数放到集合set_nums中,遍历set_nums中的元素,如果其中一个元素值-1结果在set_nums中,则跳过,为什么呢,因为他不是起始元素,因为我们统计的时候是从连续序列的最小的元素统计的。对于不在set_nums中元素,我们就一步步累加查看是否在set_nums中,最后得到结果
看代码应该很容易看懂
关键在为什么是O(n)
首先在longestConsecutive函数中已经有一个for循环为
leetcode 官方解题是说:
因为只有当 current_num 遇到了一个序列的开始, while 循环才会被执行(也就是 current_num-1 不在数组 nums 里), while 循环在整个运行过程中只会被迭代 n 次。这意味着尽管看起来时间复杂度为O(n⋅n) ,实际这个嵌套循环只会运行O(n+n)=O(n) 次。所有的计算都是线性时间的,所以总的时间复杂度是O(n) 的。
看两个极端,[1,2,3,4,5,6]和[1,3,5,7,9]
- [1,2,3,4,5,6]中,while会遍历n-1次,外层循环for 会遍历至多n次(因为是集合,重复的元素只算一次)。在只有其中一种情况是1的时候,while会遍历n-1次,其他while都不参与。所以是O(n)
- [1,3,5,7,9]中,while会遍历0次,外层循环for 会遍历至多n次 O(n)
- 极端之外的情况类似[1,2,3,7,9]也一样
代码
class Solution:
def longestConsecutive(self, nums: List[int]) -> int:
set_nums = set(nums)
longest_streak = 0
for num in set_nums:
if num - 1 not in set_nums:
current_num = num
current_streak = 1
while (current_num + 1) in set_nums:
current_num += 1
current_streak += 1
longest_streak = max(longest_streak, current_streak)
return longest_streak