算法实战入门第二篇:链表结构与五大经典应用
链表作为一种基础而灵活的数据结构,在算法与面试题中频繁出现。它与数组最大的区别在于:数组是连续内存存储,而链表通过指针动态连接节点,更适合频繁插入与删除的场景。
本文将带你从链表的基本结构与操作入手,再通过 五道高频经典题 进行实战演练,帮助你在面试和实际开发中都能熟练掌握链表。
一、链表基础结构
1. 单链表
每个节点包含 值 + 指向下一个节点的指针。
public class ListNode {public int val;public ListNode next;public ListNode(int val = 0, ListNode next = null) {this.val = val;this.next = next;}
}
特点:
插入、删除操作灵活(O(1)),但查找需要遍历(O(n))。
2. 双链表
每个节点包含 前驱指针 + 值 + 后继指针。
优点是支持反向操作,缺点是额外占用空间。
📌 小技巧:虚拟头节点(Dummy Node)
在很多题目中,我们会引入一个哨兵节点,简化头结点的插入和删除逻辑,避免边界问题。
二、链表常见操作
遍历链表:从头节点逐一访问,时间复杂度 O(n)。
头插法 / 尾插法:在头部或尾部插入节点,O(1)。
删除节点:找到前驱节点并修改指针,O(1)。
查找节点:线性查找,O(n)。
👉 在算法题中,这些操作往往与指针技巧结合使用,形成套路化解法。
三、五道高频经典链表题
1. 反转链表(LeetCode 206)
使用三指针迭代反转。
public ListNode ReverseList(ListNode head) {ListNode prev = null;ListNode curr = head;while (curr != null) {ListNode nextTemp = curr.next;curr.next = prev;prev = curr;curr = nextTemp;}return prev;
}
时间复杂度:O(n)
空间复杂度:O(1)
2. 合并两个有序链表(LeetCode 21)
双指针比较大小,利用虚拟头节点。
public ListNode MergeTwoLists(ListNode l1, ListNode l2) {ListNode dummy = new ListNode(-1);ListNode curr = dummy;while (l1 != null && l2 != null) {if (l1.val < l2.val) {curr.next = l1;l1 = l1.next;} else {curr.next = l2;l2 = l2.next;}curr = curr.next;}curr.next = (l1 != null) ? l1 : l2;return dummy.next;
}
3. 删除倒数第 N 个节点(LeetCode 19)
快慢指针:fast 先走 n+1 步,再和 slow 同时前进。
public ListNode RemoveNthFromEnd(ListNode head, int n) {ListNode dummy = new ListNode(0, head);ListNode fast = dummy, slow = dummy;for (int i = 0; i <= n; i++) fast = fast.next;while (fast != null) {fast = fast.next;slow = slow.next;}slow.next = slow.next.next;return dummy.next;
}
4. 环检测与环入口定位(LeetCode 141 / 142)
Floyd 快慢指针法。
public ListNode DetectCycle(ListNode head) {ListNode slow = head, fast = head;while (fast != null && fast.next != null) {slow = slow.next;fast = fast.next.next;if (slow == fast) { // 相遇说明有环ListNode p1 = head;ListNode p2 = slow;while (p1 != p2) {p1 = p1.next;p2 = p2.next;}return p1; // 环入口}}return null;
}
5. 链表相交判断(LeetCode 160)
双指针技巧:走完自己的链表后跳到对方链表。
public ListNode GetIntersectionNode(ListNode headA, ListNode headB) {if (headA == null || headB == null) return null;ListNode p1 = headA, p2 = headB;while (p1 != p2) {p1 = (p1 == null) ? headB : p1.next;p2 = (p2 == null) ? headA : p2.next;}return p1;
}
四、实战技巧总结
画图理解:尤其是快慢指针、链表反转,画图能迅速理清思路。
虚拟头节点万能技巧:简化插入和删除逻辑。
递归 vs 迭代:递归代码简洁,但存在栈开销,工程实践推荐迭代。
复杂度分析必备:每写完题目,习惯性写出时间/空间复杂度。
五、结语与推荐练习
链表是算法学习的必修课,五道经典题覆盖了链表 80% 的考点。掌握它们,你不仅能应对面试,还能在实际项目中游刃有余。
📌 推荐刷题:
LeetCode 206、21、19、141、142、160
✨ 至此,链表的核心知识与经典题目你已经掌握。接下来,继续前进,逐步构建你的算法实战体系。