版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/liyunlong41/article/details/85636496
题目地址:https://leetcode.com/problems/longest-consecutive-sequence/
方法1:并查集
这个题的难点在于当更新了某个val后,不能及时更新val周围连续的数值,如val+1, val+2, val-1, val-2等。这里采用并查集的思想,将每一段连续的数值,看做是一个集合,每个集合中有一个leader或者parent。当val值有更新时,判断两边是否有集合,如果有集合那么将这个val合并到集合中,并更新集合中leader的值,如果两边都有集合,那么需要合并两个集合。
ps:并查集的复杂度接近O(1),所以总体复杂度是O(n) leetcode耗时12ms
func longestConsecutive(nums []int) int {
n := len(nums)
if n == 0 {
return 0
}
pre := make(map[int]int)
count := make(map[int]int)
for _, val := range nums {
pre[val] = -100000
}
max := 0
for _, val := range nums {
if count[val] > 0 {
continue
}
nowVal := 1
var leftLeader, rightLeader int
if count[val - 1] > 0 {
leftLeader = find(val - 1, pre) //左边集合的leader
nowVal += count[leftLeader]
}
if count[val + 1] > 0 {
rightLeader = find(val + 1, pre)
nowVal += count[rightLeader]
}
// fmt.Println("l:", leftLeader, "r:", rightLeader)
count[val] = nowVal
if count[val - 1] > 0 {
pre[leftLeader] = val
}
if count[val + 1] > 0 {
pre[val] = rightLeader //集合合并
count[rightLeader] = count[val]
}
if max < count[val] {
max = count[val]
}
}
return max
}
func find(val int, pre map[int]int) int {
if pre[val] == -100000 {
return val
}
ret := find(pre[val], pre)
pre[val] = ret //更新pre数组指向集合leader
return ret
}
方法2:参考了别人的解法,很巧妙。利用一个map,将所有的数值添加到map中,再次遍历原先数组,先判断当前的值val前面的数val-1是否存在,存在则continue,这是为了保证当前的val是连续序列的最小值。当val是某一段连续序列的最小值时,我们在map中一直找val+1, val+2, val+3...直到找不到,记录这段连续的最长序列,更新答案,另外需要将找到的值在map中删除。
由于每次都是从某段序列的最小值开始找,找不到就退出,找到的就删除,所以最大的复杂度是map的大小。即O(n) 耗时8ms
func longestConsecutive(nums []int) int {
count := make(map[int]int)
for _, val := range nums {
count[val] = 1
}
max := 0
for _, val := range nums {
if _, found := count[val - 1]; found {
continue
}
tmp := 1
tmp2 := val + 1
for {
if _, found := count[tmp2]; !found {
break
}
delete(count, tmp2)//这里需要删除,防止1,2,3...100000,1,1,1,1,1....
tmp++
tmp2++
}
if max < tmp {
max = tmp
}
}
return max
}