第一思路:排序法(超时)
func longestConsecutive(nums []int) int {
if len(nums) <= 1{
return len(nums)
}
continueListLenMap := make(map[int]int) // index: 以此为起点的连续子数组长度
sort.Slice(nums, func(i,j int) bool{
return nums[i] < nums[j]
})
for idx, _ := range nums{
lens := 1
for j:=idx+1;j<len(nums);j++{
if nums[j] - nums[j-1] == 1{
lens++
} else if nums[j] == nums[j-1]{
continue
} else{
break
}
}
continueListLenMap[idx] = lens
}
res := 0
for _, v := range continueListLenMap{
if v > res{
res = v
}
}
return res
}
解法一:哈希法
对原数组排序之后连续的序列就很容易找到了。不过排序的时间复杂度是 O(NlogN),而题目要求我们时间复杂度为 O(N),这就得另想办法了
想找连续序列,首先要找到这个连续序列的开头元素,然后递增,看看之后有多少个元素还在 nums 中,即可得到最长连续序列的长度了。
我们可以用空间换时间的思路,把数组元素放到哈希集合里面,然后去寻找连续序列的第一个元素
例如nums = [8,4,9,1,3,2],我们先找到 1,然后递增,找到了 2, 3, 4,这就是一个长度为 4 的连续子序列。又继续递增,中间5,6,7没找到,直到找到 8,作为新的连续子序列起点,递增到了 9,这是一个长度为 2 的连续子序列
func longestConsecutive(nums []int) int {
if len(nums) <= 1{
return len(nums)
}
set := make(map[int]struct{})
for _, v := range nums{
set[v] = struct{}{}
}
res := 0
for num := range set{ // 遍历哈希表
if _, ok := set[num-1]; ok{ // 找的到比num更小的,说明它不是连续子序列的第一个元素
continue
}
// 找到最小的起始元素,开始计算长度
curNum := num
curLen := 1
for{ // 不断寻找下一个数是不是在哈希表中
if _, ok := set[curNum+1]; ok{
curLen++
curNum++
}else{
break
}
}
res = max(res, curLen)
}
return res
}
func max(a, b int)int{
if a > b{
return a
}
return b
}
- 时间复杂度:O(n),其中 n 是 nums 的长度。
- 在二重循环中,每个元素至多遍历两次:在外层循环中遍历一次,在内层循环中遍历一次。所以二重循环的时间复杂度是 O(n) 的。比如 nums=[1,2,3,4],其中 2,3,4 不会进入内层循环(命中continue逻辑),只有 1 会进入内层循环。所以,一般只有连续子数组的首个数字会被遍历2次
- 空间复杂度:O(n)