前端刷题路-Day80:最长连续序列(题号128)

250 阅读1分钟

这是我参与8月更文挑战的第14天,活动详情查看:8月更文挑战

最长连续序列(题号128)

题目

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

提示:

  • 0 <= nums.length <= 105
  • -109 <= nums[i] <= 109

链接

leetcode-cn.com/problems/lo…

解释

这题啊,这题可以说是根本想不到。

上来来个O(n)这谁受得了,想半天也没有思路,首先得去掉排序的操作了,因为没有任何排序算法的时间复杂度是O(n),最强也就是O(nlogn),所以肯定是不能排序的。

那剩下来的就只有while了,利用while一个个去找,但怎么找呢?

indexOf肯定是不行了,这玩意的时间复杂度不是常数型的,具体原理找了半天也找不到,估计找到了时间复杂度也不是O(1)的,果断放弃。

那剩下的就只有Map结构了,先扫一遍数组,之后将每个值都setMap上,这样以后取的时候就是O(1)的时间复杂度了,到这一步其实就比较简单了,利用while去不断的查找后的数字,累计递增即可。

不过还有一点需要注意,测试用例有可能出现巨大的情况,所以如果每个数字都使用while来查找的话,必然是会超时的,此时就应该剪枝了。

剪枝该怎么剪呢?让我们回到题目本身,它求的是一个连续的最长序列,那么在循环的时候,如果当前值并不是自己所在序列的第一个元素,那就没有必要进行后续的操作了,因为后面会有头节点的while循环,也还是会找到当前元素的。

这样基本上就完事了,在每次while后累计最大值即可,完成for循环即可拿到最终的结果。

自己的答案

更好的方法(Map+剪枝)

思路👆说了,👇看看代码:

var longestConsecutive = function(nums) {
  const map = new Map()
  for (const num of nums) {
    map.set(num, true)
  }
  let maxLength = 0
  for (const num of map.keys()) {
    if (!map.has(num - 1)) {
      let currentLength = 1
      let currentValue = num
      while (map.has(currentValue + 1)) {
        currentValue++
        currentLength++
      }
      maxLength = Math.max(maxLength, currentLength)            
    }
  }
  return maxLength
};

代码整体和上面说的一样,利用currentLength来记录当前序列的长度;currentValue来记录当前序列最后一个值的大小,然后持续使用while迭代,直到找不到最后一个值。

这里的时间复杂度计算是这样的:

  • 第一个for循环,O(n)
  • 第二个for循环,O(n)
  • while循环,非指数型增长,不计

有多种时间复杂度的情况下,取最大的即可,这里最大的就是O(n)了,所以最后的时间复杂度是O(n)

更好的方法(Set+剪枝)

用了Map自然也能用Set了,因为Set自己也有has方法,代码几乎不需要进行更改👇:

var longestConsecutive = function(nums) {
  const set = new Set(nums)
  let maxLength = 0
  for (const num of set) {
    if (!set.has(num - 1)) {
      let currentLength = 1
      let currentValue = num
      while (set.has(currentValue + 1)) {
        currentValue++
        currentLength++
      }
      maxLength = Math.max(maxLength, currentLength)            
    }
  }
  return maxLength
};

相比Map来说少了一次for循环,但其实Set内部也是需要处理的,这里忽略不计,重点是这二者内存占用不同,因为Map多存了true这个值,所以内存占用会比Set大很多,二者的差距也就在这个地方。

这两个方法的思路是没有区别的,但就是因为数据结构的选择,导致了内存占用上超过50%的差距。



PS:想查看往期文章和题目可以点击下面的链接:

这里是按照日期分类的👇

前端刷题路-目录(日期分类)

经过有些朋友的提醒,感觉也应该按照题型分类
这里是按照题型分类的👇

前端刷题路-目录(题型分类)