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
示例 3:
输入:nums = [1,0,1,2]
输出:3
提示:
0 <= nums.length <= 105-109<= nums[i] <= 109
题解
我们需要在 \(O(1)\) 的时间内查找某个数是否存在。因此,首先将数组中的所有元素放入一个 HashSet 中。这不仅能去重,还能支持快速查找。
避免冗余计算 (关键优化)
如果我们对集合中的每一个数都尝试去向后计数(例如,对于 x,尝试找 x+1, x+2...),最坏情况下的时间复杂度会退化到 \(O(n^2)\)。
优化策略:
我们只从序列的起点开始计数。
对于集合中的元素 x,如果 x - 1 也在集合中,说明 x 并不是一个连续序列的起点(x-1 才是更前面的元素),我们可以直接跳过 x。
只有当 x - 1 不在 集合中时,我们才开始向后匹配 x + 1, x + 2 等等。
算法步骤
- 初始化:将
nums转化为HashSet(去重且查找快)。 - 遍历:遍历
HashSet中的每一个元素num。 - 判断起点:检查
num - 1是否存在于集合中。- 如果存在:说明
num不是起点,跳过。 - 如果不存在:说明
num是序列的起点。
- 如果存在:说明
- 向后延伸:从
num开始,不断检查num + 1,num + 2是否存在,直到断裂。记录当前序列长度。 - 更新最大值:维护一个全局变量
longest_streak,记录遇到的最长长度。
class Solution:
def longestConsecutive(self, nums: List[int]) -> int:
# 1. 将数组转换为集合,去重并实现 O(1) 查找
num_set = set(nums)
longest_streak = 0
# 2. 遍历集合中的每个数
for num in num_set:
# 3. 只有当 num 是序列的起点时(即 num-1 不在集合中),才开始计数
if num - 1 not in num_set:
current_num = num
current_streak = 1
# 4. 向后寻找连续的数字
while current_num + 1 in num_set:
current_num += 1
current_streak += 1
# 5. 更新最大长度
longest_streak = max(longest_streak, current_streak)
return longest_streak
41. 缺失的第一个正数
题目
给你一个未排序的整数数组 nums ,请你找出其中没有出现的最小的正整数。
请你实现时间复杂度为 O(n) 并且只使用常数级别额外空间的解决方案。
示例 1:
输入:nums = [1,2,0]
输出:3
解释:范围 [1,2] 中的数字都在数组中。
示例 2:
输入:nums = [3,4,-1,1]
输出:2
解释:1 在数组中,但 2 没有。
示例 3:
输入:nums = [7,8,9,11,12]
输出:1
解释:最小的正数 1 没有出现。
提示:
1 <= nums.length <= 105-231<= nums[i] <= 231- 1
题解
分析: 原地哈希
- 遍历数组,将所有小于等于
0或大于len(nums)的数替换为len(nums)+1,因为这些数对结果没有影响 - 再次遍历数组,对于每个数
num,计算其绝对值abs_num,为什么进行绝对值操作呢?因为在后续的标记过程中,我们会将某些位置的数变为负数
- 如果
1 <= abs_num <= len(nums),则将nums[abs_num - 1]标记为负数,表示abs_num存在于数组中
为什么要这么做呢?因为数组长度为\(n\),最小的缺失正整数只能在\(1\)到\(n+1\)之间,所以我们只需要关注\(1\)到\(n\)的数,所以将不在这个范围内的数替换掉,通过将对应位置的数标记为负数,我们可以在后续的遍历中快速判断某个数是否存在于数组中
- 如果
- 最后遍历数组,找到第一个正数的位置i,则i+1即为缺失的最小正整数
class Solution(object):
def firstMissingPositive(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
n = len(nums)
for i in range(n):
if nums[i] <= 0 or nums[i] > n:
nums[i] = n + 1
for i in range(n):
abs_num = abs(nums[i])
if 1 <= abs_num <= n:
nums[abs_num - 1] = -abs(nums[abs_num - 1])
for i in range(n):
if nums[i] > 0:
return i + 1
return n + 1