给定一个未排序的整数数组,找出最长连续序列的长度。
要求算法的时间复杂度为 O(n)。
输入: [100, 4, 200, 1, 3, 2]
输出: 4
解释: 最长连续序列是 [1, 2, 3, 4]。它的长度为 4。
方法1:排序
时间复杂度O(nlogn),不满足要求,但能通过,比较好想
思路
从小到大排序
遍历数组,比较相邻的两项,如果相同,则跳过,继续遍历下一项
如果 当前项+1 等于 下一项,说明遇到连续项,count +1
否则,说明连续中断,将 count 重置为 1
方法1 代码
var longestConsecutive = (nums) => {
if (nums.length === 0) return 0
nums.sort((a, b) => a - b)
let max = 1
let count = 1
for (let i = 0; i < nums.length - 1; i++) {
let cur = i, next = i + 1
if (nums[cur] === nums[next]) continue // 相同就跳过本次循环
if (nums[cur] + 1 === nums[next]) { // 发现连续项 count++
count++
} else { // 否则,count重置1
count = 1
}
max = Math.max(max, count)
}
return max
}
方法2:Set 的查找是 O(1)
Set 查找元素的时间复杂度是 O(1),JS 的 Set 能给数组去掉重复元素
将数组元素存入 set 中,遍历数组 nums
如果 nums[i] - 1 存在于 set ,说明 nums[i] 不是连续序列的起点,跳过,继续遍历
当前项没有“左邻居”,它就是连续序列的起点
不断在 set 中查看 cur + 1 是否存在,存在,则 count +1
cur 不再有 “右邻居” 了,就算出了一段连续序列的长度
也可以找到一个数后分别左右查找,并删除找到的
方法2 代码
var longestConsecutive = (nums) => {
const set = new Set(nums) // set存放数组的全部数字
let max = 0
for (let i = 0; i < nums.length; i++) {
if (!set.has(nums[i] - 1)) { // nums[i]没有左邻居,是序列的起点
let cur = nums[i]
let count = 1
while (set.has(cur + 1)) { // cur有右邻居cur+1
cur++ // 更新cur
count++
}
max = Math.max(max, count) // cur不再有右邻居,检查count是否最大
}
}
return max
}
方法3:哈希表
哈希表的value存什么
key存数字,value存什么?
新存入的数字,它找到相邻的数,它希望从邻居数那里获取什么信息
很显然它希望,左邻居告诉它左边能提供的连续长度,右邻居告诉它右边能提供的连续长度
加上它自己的长度,就有了自己处在的连续序列的长度
更新新序列的两端数字的value
同处一个连续序列的数字的value理应都相同,这是它们共同特征
但没有必要每个的value都是序列长度,只需要两端的数存序列的长度就好
因为靠的是两端和新数对接,序列是连续的,中间没有空位
序列的一端找到邻居后,将另一端对应的value更新为最新的序列长度
方法3 代码
var longestConsecutive = (nums) => {
let map = new Map()
let max = 0
for (const num of nums) { // 遍历nums数组
if (!map.has(num)) { // 重复的数字不考察,跳过
let preLen = map.get(num - 1) || 0 // 获取左邻居所在序列的长度
let nextLen = map.get(num + 1) || 0 // 获取右邻居所在序列的长度
let curLen = preLen + 1 + nextLen // 新序列的长度
map.set(num, curLen) // 将自己存入 map
max = Math.max(max, curLen) // 和 max 比较,试图刷新max
map.set(num - preLen, curLen) // 更新新序列的左端数字的value
map.set(num + nextLen, curLen) // 更新新序列的右端数字的value
}
}
return max
}
方法4 并查集
我不会,待补充,下方评论区已有详细补充
这位大佬有讲,可以点进去看:[LeetCode 128] Longest Consecutive Sequence [并查集][OTTFF]
class Solution {
Map<Integer,Integer> findMap=new HashMap<>();
Map<Integer,Integer> sizeMap=new HashMap<>();
int max=1;
public int longestConsecutive(int[] nums) {
//方法2:并查集
if (nums.length<1)
return 0;
for (int item:nums) {
findMap.put(item,item);
sizeMap.put(item,1);
}
for(int item:nums){
if (findMap.containsKey(item-1)){
union(item,item-1);
}
}
return max;
}
public int find(int son){//带路径优化的查找
int parent=findMap.get(son);
if (parent!=son)
parent = find(parent);
findMap.put(son,parent);
return parent;
}
public void union(int root1,int root2){
int father1=find(root1);
int father2=find(root2);
if (father1!=father2){
int size1=sizeMap.get(father1);
int size2=sizeMap.get(father2);
//按秩合并,将深度小的合并到深度大的上去
if (size1>size2){
findMap.put(father2,father1);
sizeMap.put(father1,size1+size2);
}else {
findMap.put(father1,father2);
sizeMap.put(father2,size1+size2);
}
max=Math.max(max,size1+size2);
}
}
}
find方法递归改迭代
public int find(int son){//带路径优化的查找
//迭代求解
int parent=findMap.get(son);
while (parent!=son){
son=parent;
parent=findMap.get(son);
}
findMap.put(son,parent);
return parent;
}
作者:hyj8
链接:https://leetcode-cn.com/problems/longest-consecutive-sequence/solution/fang-fa-cong-yi-dao-nan-bing-cha-ji-fang-fa-bu-hui/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。