链表刷题总结

0 Linked List Basic 链表是什么? 链表是一种通过指针将节点串联起来的线性数据结构。每个节点包含数据和指向下一个节点的指针 head ↓ [1] → [2] → [3] → [4] → None 与数组的对比: 操作 数组 链表 按下标访问 O(1) O(n) 头部插入/删除 O(n) O(1) 中间插入/删除(已知位置) O(n) O(1) 空间 连续内存 分散内存 Python 中的链表节点 1class ListNode: 2 def __init__(self, val=0, next=None): 3 self.val = val 4 self.next = next 链表的核心操作 1# 遍历 2cur = head 3while cur: 4 print(cur.val) 5 cur = cur.next 6 7# 在 node 后面插入 new_node 8new_node.next = node.next 9node.next = new_node 10 11# 删除 node 的下一个节点 12node.next = node.next.next 链表题的三大神器 哑节点(Dummy Node):在链表头部加一个虚拟节点,避免处理"头节点可能被删除/改变"的特殊情况 1dummy = ListNode(0) 2dummy.next = head 3# ... 操作 ... 4return dummy.next # 新的头节点 快慢指针:两个指针以不同速度遍历链表 1# 找链表中点(慢指针走一步,快指针走两步) 2slow = fast = head 3while fast and fast.next: 4 slow = slow.next 5 fast = fast.next.next 6# slow 现在指向中点(偶数个节点时是中间偏左) 7 8# 检测环 9slow = fast = head 10while fast and fast.next: 11 slow = slow.next 12 fast = fast.next.next 13 if slow == fast: 14 return True # 有环 递归:链表天然适合递归,处理当前节点 + 递归处理剩余链表。 1def process(node): 2 if not node: 3 return None # base case 4 # 递归处理剩余部分 5 node.next = process(node.next) 6 # 处理当前节点 7 return node 1 快慢指针系 1.1 环形链表 | Easy 题目:给链表头节点 head,判断链表中是否有环。要求 $O(1)$ 空间 ...

滑动窗口刷题总结

0 Sliding Windows Basic 什么是滑动窗口? 滑动窗口本质上是双指针的特殊形式:两个指针left和right同向移动,维护一个连续的区间[left, right)或[left, right] right负责扩张窗口纳入新元素,left负责收缩窗口排除不合法元素 $O(n^2) \Rightarrow O(n)$ 滑动窗口的两种类型: 类型 窗口大小 典型题 固定窗口 窗口大小 k 已知 字符串中所有字母异位词 可变窗口 窗口大小动态变化 无重复字符的最长子串 什么时候使用滑动窗口?关键词 前提是问题有单调性:窗口扩大时某个量单调变化(比如和变大、字符种类不减);如果数组含负数导致"扩大窗口和不一定变大", 滑动窗口就失效了, 得换前缀和 + 哈希 连续子数组/子串 最长/最短的满足某条件的子串(不含重复元素/和大于等于target/至多k个不同元素) 包含/不包含某些字符的子串 固定窗口大小"或"可变窗口大小 模板:右指针负责扩展窗口,左指针负责收缩窗口,两者配合保证窗口始终满足某种约束 1def sliding_window(s): 2 window = {} # 维护窗口内的状态(计数、和等) 3 left = 0 4 ans = 0 5 for right in range(len(s)): 6 # 右端点元素进入窗口,更新状态 7 window[s[right]] = window.get(s[right], 0) + 1 8 9 # 当窗口不满足条件时,收缩左端点 10 while 窗口不合法: 11 window[s[left]] -= 1 12 left += 1 13 14 # 窗口合法,更新答案 15 ans = max(ans, right - left + 1) 16 return ans 1 无重复字符的最长子串 | Medium 题目:给定字符串 s,找出不含有重复字符的最长子串的长度。 ...

双指针刷题总结

0 Two Pointers Basic 双指针是什么? 用两个指针(下标)在数组/链表上协同移动,通过缩小搜索范围来降低复杂度 两大类型: 类型 特征 典型题 对撞指针 一头一尾,向中间逼近 盛水容器、三数之和 快慢指针 同向移动,速度不同 移动零、链表环检测 使用双指针的条件: 通常数组有序(或者问题本身有单调性) 如果无序,往往需要先排序 双指针能降低复杂度原因:利用了单调性,使得指针不需要回退,将 O(n²) 降到 O(n) 1 快慢指针(数组原地操作) 1.1 移动零 | Easy 题目: 将数组中所有 0 移到末尾,保持非零元素的相对顺序。原地操作 [0, 1, 0, 3, 12] → [1, 3, 12, 0, 0] 思路分析: 用快慢指针,left指向当前最左边的0的位置,i找非0,然后swap left:慢指针,始终指向下一个非零元素该放的位置 i: 快指针,遍历数组寻找非零元素 left左边都是已经处理好的非零元素,每找到一个非零元素,就交换到left位置,然后left右移 走一遍[0, 1, 0, 3, 12]: i=0, nums[0]=0 → 是0,跳过 zero=0, [0, 1, 0, 3, 12] i=1, nums[1]=1 → 非0,和zero交换 zero=1, [1, 0, 0, 3, 12] i=2, nums[2]=0 → 是0,跳过 zero=1, [1, 0, 0, 3, 12] i=3, nums[3]=3 → 非0,和zero交换 zero=2, [1, 3, 0, 0, 12] i=4, nums[4]=12 → 非0,和zero交换 zero=3, [1, 3, 12, 0, 0] 踩坑记录:搞清楚两个指针的含义以及交换条件 ...