力扣hot100—最长连续序列

112 阅读3分钟

算法每日一更,记录我的成长。很久很久没更新了,这一年多以来忙于工作,慢慢忘记了,不过从现在开始,我将保持每天记录一个算法(一周5个)。

那么今天带来的是力扣热题100的最长连续序列。题目描述如下:

给定一个未排序的整数数组 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

题目解析:这里题目有点歧义,最长连续序列可能不太好理解。我举个例子,大家都玩过斗地主吧,这个最长连续序列就是最长的一个“顺子”。我们结合实例1的例子来看,[100,4,200,1,3,2],从结果看它的值是4,就是[1,2,3,4]这个序列了,至于100,不是4的连续数5因此不能算进去。另外[100,1,4,200,1,3,2]这个序列我们也认为是4,不包含重复元素,试想一下,你在斗地主的时候打出一个顺子的时候,可以含有两个相同数吗,这显然是不可以的。好的题目的意思我们理解了,那接下来我们开始cty

注意:因为题目规定了时间复杂度为O(n),因此不允许使用排序算法,排序将达到了O(nlogn),不符合题目。当然排序很简单,答题思路为先讲数组进行去重排序,遍历当前元素x的下一个元素y的值是不是x+1,如果不是则结束循环,则长度为 y-x+1

思路:对于 nums 中的元素 x(应该是最小的元素),以 x 为起点,不断查找下一个数 x+1,x+2,⋯ 是否在 nums 中,并统计序列的长度。

为了做到 O(n) 的时间复杂度,需要两个关键优化

1.把 nums 中的数都放入一个哈希集合中,这样可以 O(1) 判断数字是否在 nums 中。

2.如果 x−1 在哈希集合中,则不以 x 为起点。为什么?因为以 x−1 为起点计算出的序列长度,一定比以 x 为起点计算出的序列长度要长!这样可以避免大量重复计算。比如 nums=[3,2,4,5],从 3 开始,我们可以找到 3,4,5 这个连续序列;而从 2 开始,我们可以找到 2,3,4,5 这个连续序列,一定比从 3 开始的序列更长。

上代码!

/**
 * @param {number[]} nums
 * @return {number}
 */
var longestConsecutive = function(nums) {
   // 1.先用 set 去存一份nums,后续可以实现O(n)遍历
   const set = new Set(nums)
   
   // 2.定义最后结果,初始值先设置为0,因为可能存在[]的空数组对吧
   let ans = 0
   
   // 3.遍历set,以 x 为起点,不断查找下一个数
   for(const x of set) {
       // 直接以最小元素为起点
       if(set.has(x)) continue
       
       // 以 x 为起点
       let y = x + 1
       while(set.has(y)) y++
       ans = Math.max(ans, y - x)
   }
   return ans
};

最后我们提交代码,运行看结果。

image.png

启动!

image.png