LeetCode day3-最长连续序列

从 LeetCode #128 学算法与 Python:哈希表、O(n) 思维与函数/方法的本质区别

关键词 :最长连续序列|哈希表|时间复杂度 O(n)|set|函数调用 vs 方法调用|Python 基础


一、引子:一道题,两个层次的收获

最近在刷 LeetCode 第 128 题 「最长连续序列」 时,我不仅学会了一种巧妙的 O(n) 解法,还意外暴露了自己对 Python 基础语法的一些模糊认知------比如:

  • 为什么 set(nums) 正确,而 nums.set() 会报错?
  • len() 是函数还是方法?为什么不能写成 arr.len()
  • 两层循环怎么可能是 O(n)?

这些问题看似琐碎,实则关乎编程底层逻辑的理解。于是,我决定把这道题的解法和背后的 Python 原理一起梳理清楚。


二、题目回顾:最长连续序列(LeetCode #128)

题目 :给定一个未排序的整数数组 nums,找出数字连续的最长序列的长度。
要求时间复杂度为 O(n)

示例:

python 复制代码
输入: [100, 4, 200, 1, 3, 2]
输出: 4  # 因为 [1,2,3,4] 是最长连续序列

三、核心解法:哈希表 + 起点判断(O(n))

✅ 为什么不能排序?

  • 排序最低时间复杂度是 O(n log n),不满足题目要求。
  • 必须用 空间换时间 → 引入哈希表(Python 中用 set 实现)。

✅ 我的四步解题法

步骤 1:用 set(nums) 去重并支持 O(1) 查找
python 复制代码
num_set = set(nums)
  • 自动去除重复数字(重复值不影响连续长度)
  • 后续可用 x in num_setO(1) 时间判断是否存在

💡 注意:这里必须写 set(nums)不是 nums.set()(后面详解原因)

步骤 2:只从"连续序列的起点"开始扩展
  • 起点定义num 是起点 ⇨ num - 1 不在集合中
  • 这样可避免重复计算(如从 2 开始数 [2,3,4],不如从 1 开始数 [1,2,3,4])
步骤 3:用 while 向右扩展
python 复制代码
while current_num + 1 in num_set:
    current_num += 1
    current_length += 1
  • 只要下一个数存在,就继续延伸
步骤 4:更新全局最大长度
python 复制代码
max_length = max(max_length, current_length)

✅ 完整代码

python 复制代码
from typing import List

class Solution:
    def longestConsecutive(self, nums: List[int]) -> int:
        num_set = set(nums)
        max_length = 0

        for num in num_set:
            if num - 1 not in num_set:          # 判断是否为起点
                current_num = num
                current_length = 1

                while current_num + 1 in num_set:  # 向右扩展
                    current_num += 1
                    current_length += 1

                max_length = max(max_length, current_length)

        return max_length

四、为什么时间复杂度是 O(n)?

虽然有 for + while 两层循环,但:

  • 每个数字最多被访问两次
    1. 外层循环判断是否为起点
    2. 内层循环作为连续序列的一部分被扩展
  • 总操作次数 ≤ 2n时间复杂度 O(n)

🌟 这是"看似嵌套循环,实则线性时间"的经典案例!


五、关键 Python 基础:函数调用 vs 方法调用

在写这道题时,我一度困惑:为什么是 set(nums) 而不是 nums.set()?这引出了一个根本问题:

🔍 函数(Function) vs 方法(Method)

类型 调用形式 特点 示例
函数 function_name(参数) 独立工具,通用操作 len(arr), sorted(s), set(nums)
方法 对象.method() 对象自带的功能 arr.append(x), "abc".upper(), s.add(x)

✅ 常见函数(你刷题必用)

python 复制代码
len(obj)          # 获取长度 → len([1,2]) → 2
sorted(iterable)  # 返回新排序列表
set(iterable)     # 转为集合(去重 + O(1) 查找)
list(iterable)    # 转为列表
range(n)          # 生成数字序列
enumerate(arr)    # 枚举 (index, value)

✅ 常见方法(按数据结构分类)

python 复制代码
# list
arr.append(x), arr.pop(), arr.sort()

# str
s.upper(), s.split(), s.replace()

# set
s.add(x), s.remove(x), s.union(other)

# dict
d.get(key), d.keys(), d.items()

❌ 常见错误(千万别写!)

python 复制代码
[1,2].len()       # ❌ 应写 len([1,2])
"bac".sorted()    # ❌ 应写 sorted("bac")
[1,2,2].set()     # ❌ 应写 set([1,2,2])

💡 口诀
通用操作用函数(len, set, sorted),对象专属用方法(.append, .upper


六、为什么 set(nums) 是函数,不是方法?

  • set 是 Python 的内置类型

  • set(nums) 是调用其构造函数,将可迭代对象转为集合

  • list 类型没有 .set() 方法 ,所以 nums.set() 会报错:

    python 复制代码
    AttributeError: 'list' object has no attribute 'set'

类似地:

  • list("ab") ✅,但 "ab".list()
  • str(123) ✅,但 123.str()

七、本题带给我的双重成长

算法层面 Python 语言层面
✅ 学会"只从起点扩展"的 O(n) 思想 ✅ 分清函数 vs 方法
✅ 理解哈希表在去重与快速查找中的作用 ✅ 掌握 set(nums) 的正确用法
✅ 能分析"嵌套循环但线性时间"的复杂度 ✅ 避免 AttributeError 类低级错误

八、总结:刷题不仅是练算法,更是练语言

这道「最长连续序列」让我明白:

优秀的解法 = 清晰的算法思维 + 扎实的语言基础

  • 如果不懂 set 的 O(1) 查找特性,就想不到 O(n) 解法;
  • 如果混淆函数与方法,就会写出语法错误,浪费调试时间。

因此,刷题时不要只盯着"通过",更要问自己:

  • 这个数据结构为什么适合这个问题?
  • 这个函数/方法的底层原理是什么?
  • 我能否把这种模式迁移到其他题目?
相关推荐
随意起个昵称2 小时前
【题解学习】序列题
学习·算法
思通数科多模态大模型2 小时前
门店 AI 清洁系统:AI 语义分割 + 机器人清洁
大数据·人工智能·算法·目标检测·计算机视觉·自然语言处理·机器人
六毛的毛2 小时前
比较含退格的字符串
开发语言·python·leetcode
iAkuya2 小时前
(leetcode)力扣100 27合并两个有序链表(迭代/递归)
算法·leetcode·链表
Brduino脑机接口技术答疑2 小时前
TDCA 算法在 SSVEP 场景中的 Padding 技术:原理、应用与工程实现
人工智能·算法·机器学习·数据分析·脑机接口
挖矿大亨2 小时前
C++中深拷贝与浅拷贝的原理
开发语言·c++·算法
发疯幼稚鬼2 小时前
图的存储与拓扑排序
数据结构·算法·排序算法·拓扑学
Bruce_kaizy2 小时前
c++图论——生成树之Kruskal&Prim算法
c++·算法·图论
LYFlied3 小时前
【每日算法】LeetCode 5. 最长回文子串(动态规划)
数据结构·算法·leetcode·职场和发展·动态规划