「这是我参与2022首次更文挑战的第20天,活动详情查看:2022首次更文挑战」。
题目
给定一个未排序的整数数组 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
思路
要寻找最长的连续序列,很明显,如果数组 nums
是有序的话,那么只要遍历一次,按照寻找 x, x + 1, x + 2 ...
的规律去统计每个连续序列的长度,每次都取最大的即可;
无序数组转变为有序,使用 Array.sort
的话,显然不满足题目要求时间复杂度为 O(n)
的要求,但是思路是比较常规的。
排序后比较解法
var longestConsecutive = function(nums) {
if(nums.length == 0) return 0;
// 排序
nums.sort((a, b) => a - b);
// 最长连续序列长度
let max = 1;
// 当前某个序列的连续长度
let curMax = 1;
for(let i = 0; i < nums.length; i++) {
let cur = nums[i], next = nums[i + 1];
// 重复的直接跳过
if(cur === next) continue;
// 满足连续序列
if(cur + 1 === next) {
curMax++;
} else {
// 不满足,重置curMax
curMax = 1;
}
max = Math.max(max, curMax);
}
return max;
}
思考: 如果不对数组进行排序,该怎么做?例如,当前 nums[i] == 2
时,该序列的下一个值应该为 3
,那么 nums
中有没有 3
呢?要遍历去寻找么?显然不能遍历寻找,否则时间复杂度又不满足题目要求了。但可以先把 nums
转变为 Set
结构,在查找时,使用 Set.has
就可以了;于是如下思路便很容易想到
使用Set
var longestConsecutive = function(nums) {
if(nums.length == 0) return 0;
// 先转换为Set结构
let stack = new Set(nums), max = 1;
for(let i = 0; i < nums.length; i++) {
let curMax = 1, curNum = nums[i];
while(stack.has(curNum + 1)) {
curMax++;
curNum++;
}
max = Math.max(max, curMax);
}
return max;
}
继续思考: 上面的解法满足题目要求么?好像并不满足。循环的内部使用到的 while
,将时间复杂度拉长了;对于如下用例:
[1, 2, 3, 4, 5, 6]
在遍历到 2
时,这次的遍历是有必要的么?显然没必要,因为在遍历到 1
时,它的最长序列会包括 2
形成的最长序列;同理对于 3, 4, 5, 6
都是无效的遍历;它们有一个共同的特性,就是都不为连续序列的 起点;判断当前遍历的,是不是 序列起点,可以使用 Set.has(num[i] - 1)
是否存在判断;因为作为 起点,它的左边不能有存在连续数字。
优化Set结构后的解法
var longestConsecutive = function(nums) {
if(nums.length == 0) return 0;
// 先转换为Set结构
let stack = new Set(nums), max = 1;
for(let i = 0; i < nums.length; i++) {
// 优化:不是起点,可以跳过
if(!stack.has(nums[i] - 1)) {
let curMax = 1, curNum = nums[i];
while(stack.has(curNum + 1)) {
curMax++;
curNum++;
}
max = Math.max(max, curMax);
}
}
return max;
}
上述解法的时间复杂度是符合题目要求的,因为对于 nums[i]
来说,被枚举的次数最多为两次,一次在判断是不是 起点 时,一次在枚举 nums[i] + 1
;即时间复杂度为 O(2n)
, 2
为常数,不随 n
变化,即为 O(n)
小结
使用适合的数据结构,往往能为解法带来很大的便利;如本题的 Set
结构,在查找某个数时,将时间复杂度降低为 O(1)
,同时还对数组去重了;另外,像 Array
,可以模仿栈的结构,获得先进后出的特性;
时刻铭记: 程序 = 数据结构 + 算法
LeetCode 👉 HOT 100 👉 最长连续序列 - 中等题 ✅
合集:LeetCode 👉 HOT 100,有空就会更新,大家多多支持,点个赞👍
如果大家有好的解法,或者发现本文理解不对的地方,欢迎留言评论 😄