**摘要:**本文聚焦LeetCode热题100链表板块,解析高频考点与经典解法。


链表基础
单向链表
java
class ListNode {
int val;
ListNode next;
ListNode(int x) {
val = x;
next = null;
}
}
public class SinglyLinkedList implements Iterable<Integer> {
private ListNode head;
// ==================== 1. 头部添加 ====================
public void addFirst(int value) {
ListNode newNode = new ListNode(value);
newNode.next = this.head;
this.head = newNode;
}
// ==================== 2. 遍历相关 ====================
public void loopWhile(Consumer<Integer> consumer) {
ListNode curr = this.head;
while (curr != null) {
consumer.accept(curr.val);
curr = curr.next;
}
}
public void loopFor(Consumer<Integer> consumer) {
for (ListNode curr = this.head; curr != null; curr = curr.next) {
consumer.accept(curr.val);
}
}
private class NodeIterator implements Iterator<Integer> {
ListNode curr = head;
@Override
public boolean hasNext() {
return curr != null;
}
@Override
public Integer next() {
int value = curr.val;
curr = curr.next;
return value;
}
}
@Override
public Iterator<Integer> iterator() {
return new NodeIterator();
}
public void loopRecursion() {
recursion(this.head);
}
private void recursion(ListNode curr) {
if (curr == null) {
return;
}
System.out.print(curr.val + " ");
recursion(curr.next);
}
// ==================== 3. 尾部添加 ====================
private ListNode findLast() {
if (this.head == null) {
return null;
}
ListNode curr;
for (curr = this.head; curr.next != null; ) {
curr = curr.next;
}
return curr;
}
public void addLast(int value) {
ListNode last = findLast();
if (last == null) {
addFirst(value);
return;
}
ListNode newNode = new ListNode(value);
last.next = newNode;
}
public void addLast(int first, int... rest) {
ListNode sublist = new ListNode(first);
ListNode curr = sublist;
for (int value : rest) {
ListNode newNode = new ListNode(value);
curr.next = newNode;
curr = curr.next;
}
ListNode last = findLast();
if (last == null) {
this.head = sublist;
return;
}
last.next = sublist;
}
// ==================== 4. 根据索引操作 ====================
private ListNode findNode(int index) {
int i = 0;
for (ListNode curr = this.head; curr != null; curr = curr.next, i++) {
if (index == i) {
return curr;
}
}
return null;
}
private IllegalArgumentException illegalIndex(int index) {
return new IllegalArgumentException(String.format("index [%d] 不合法", index));
}
public int get(int index) {
ListNode node = findNode(index);
if (node != null) {
return node.val;
}
throw illegalIndex(index);
}
// ==================== 5. 插入节点 ====================
public void insert(int index, int value) {
if (index == 0) {
addFirst(value);
return;
}
ListNode prev = findNode(index - 1);
if (prev == null) {
throw illegalIndex(index);
}
ListNode newNode = new ListNode(value);
newNode.next = prev.next;
prev.next = newNode;
}
// ==================== 6. 删除节点 ====================
public void remove(int index) {
if (index == 0) {
if (this.head != null) {
this.head = this.head.next;
return;
} else {
throw illegalIndex(index);
}
}
ListNode prev = findNode(index - 1);
ListNode curr;
if (prev != null && (curr = prev.next) != null) {
prev.next = curr.next;
} else {
throw illegalIndex(index);
}
}
}
**虚拟头结点:**链表内还有一种特殊的节点称为哨兵(Sentinel)节点,也叫做哑元( Dummy)节点,它不存储数据,通常用作头尾,用来简化边界判断。

单向链表(带哨兵)
java
class ListNode {
int val;
ListNode next;
ListNode(int x) {
val = x;
next = null;
}
}
public class SinglyLinkedListSentinel implements Iterable<Integer> {
private ListNode head = new ListNode(0);
private ListNode findNode(int index) {
int i = -1;
for (ListNode curr = this.head; curr != null; curr = curr.next, i++) {
if (i == index) {
return curr;
}
}
return null;
}
//查找最后一个节点
private ListNode findLast() {
ListNode curr;
for (curr = this.head; curr.next != null; ) {
curr = curr.next;
}
return curr;
}
private IllegalArgumentException illegalIndex(int index) {
return new IllegalArgumentException(String.format("索引 [%d] 不合法", index));
}
//头部添加节点
public void addFirst(int value) {
ListNode newNode = new ListNode(value);
newNode.next = this.head.next;
this.head.next = newNode;
}
//尾部添加节点
public void addLast(int value) {
ListNode last = findLast();
ListNode newNode = new ListNode(value);
last.next = newNode;
}
//尾部添加多个节点
public void addLast(int first, int... rest) {
ListNode sublist = new ListNode(first);
ListNode curr = sublist;
for (int value : rest) {
ListNode newNode = new ListNode(value);
curr.next = newNode;
curr = curr.next;
}
ListNode last = findLast();
last.next = sublist;
}
//指定索引插入节点
public void insert(int index, int value) {
ListNode prev = findNode(index - 1); // index=0 时,prev 是哨兵节点
if (prev != null) {
ListNode newNode = new ListNode(value);
newNode.next = prev.next;
prev.next = newNode;
} else {
throw illegalIndex(index);
}
}
//指定索引删除节点
public void remove(int index) {
ListNode prev = findNode(index - 1);
ListNode curr;
if (prev != null && (curr = prev.next) != null) {
prev.next = curr.next;
} else {
throw illegalIndex(index);
}
}
//根据索引获取节点值
public int get(int index) {
ListNode node = findNode(index);
if (node != null) {
return node.val;
}
throw illegalIndex(index);
}
//while 遍历
public void loopWhile(Consumer<Integer> consumer) {
ListNode curr = this.head.next;
while (curr != null) {
consumer.accept(curr.val);
curr = curr.next;
}
}
//for 遍历
public void loopFor(Consumer<Integer> consumer) {
for (ListNode curr = this.head.next; curr != null; curr = curr.next) {
consumer.accept(curr.val);
}
}
//迭代器遍历
private class NodeIterator implements Iterator<Integer> {
ListNode curr = head.next;
@Override
public boolean hasNext() {
return curr != null;
}
@Override
public Integer next() {
int value = curr.val;
curr = curr.next;
return value;
}
}
@Override
public Iterator<Integer> iterator() {
return new NodeIterator();
}
//递归遍历
public void loopRecursion() {
recursion(this.head.next);
}
private void recursion(ListNode curr) {
if (curr == null) {
return;
}
System.out.print(curr.val + " ");
recursion(curr.next);
}
}
160 相交链表

**核心逻辑:**通过 "双指针边界对齐法" 让两个指针遍历两个链表 ------ 利用「指针遍历完自身链表后切换到另一链表头部」的特性,每次遍历可消除两个链表的长度差,逐步对齐指针的遍历边界,无需额外空间且时间复杂度最优,高效找到相交节点。
关键步骤:
边界初始化:定义两个指针分别指向两个链表头部(nodeA=headA,nodeB=headB);
边界对齐遍历:循环判断 nodeA != nodeB(未相遇),通过切换指针遍历路径对齐边界:
-
若 nodeA 遍历到自身链表末尾(nodeA == null):切换到另一链表头(nodeA=headB),消除长度差;
-
若 nodeA 未到末尾:继续遍历自身链表(nodeA=nodeA.next);
-
若 nodeB 遍历到自身链表末尾(nodeB == null):切换到另一链表头(nodeB=headA),消除长度差;
-
若 nodeB 未到末尾:继续遍历自身链表(nodeB=nodeB.next);
终止返回:当循环因 nodeA == nodeB 终止时,返回该节点(要么是相交,要么是 null 无交点)。
java
public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
if (headA == null || headB == null) {
return null;
}
ListNode nodeA = headA;
ListNode nodeB = headB;
while (nodeA != nodeB) {
nodeA = (nodeA == null) ? headB : nodeA.next;
nodeB = (nodeB == null) ? headA : nodeB.next;
}
return nodeA;
}
}
206 反转链表

**核心逻辑:**通过 "迭代式指针反转法" 从链表头节点起始遍历 ------ 利用「链表节点仅能单向指向后继节点」的特性,以头节点为起始点,借助三个指针(前驱 / 当前 / 后继)每次反转一个节点的指向,逐步推进遍历边界,无需额外空间且时间复杂度最优,高效完成链表反转。
关键步骤:
边界初始化:定义前驱指针 prev = null、当前指针 curr = head;
迭代反转遍历:循环判断 curr != null:
-
临时存储后继:定义 temp = curr.next(保存当前节点的后继节点,避免反转后丢失链表后续节点);
-
反转节点指向:curr.next = prev(将当前节点的指针从指向后继改为指向前驱,完成单次反转);
-
推进遍历边界:prev = curr (前驱指针后移,指向当前已完成反转的节点);curr = temp(当前指针后移,指向待处理的后继节点);
终止返回:当循环因 curr == null终止时,prev 已指向原链表的最后一个节点,返回 prev。
java
public ListNode reverseList(ListNode head) {
if (head == null) {
return null;
}
ListNode prev = null;
ListNode curr = head;
while (curr != null) {
ListNode temp=curr.next;
curr.next=prev;
prev=curr;
curr=temp;
}
return prev;
}
234 回文链表

核心逻辑: 利用回文的中心对称特性,先将链表节点存入数组实现随机访问,再通过双指针从数组首尾向中间收缩验证,判断是否为回文。
关键步骤:
-
边界初始化:空链表直接返回 false;定义数组和遍历指针指向链表头。
-
链表转数组:遍历链表,将所有节点存入数组。
-
双指针验证:左指针从数组头、右指针从数组尾开始,对比对应位置值,指针向中间收缩,直至相遇。
-
终止返回:验证完成则返回 true。
java
public boolean isPalindrome(ListNode head) {
List<ListNode> list = new ArrayList<>();
if (head == null) {
return false;
}
ListNode curr=head;
while (curr!=null){
list.add(curr);
curr=curr.next;
}
int left=0;
int right=list.size()-1;
while (left<=right){
if(list.get(left).val!=list.get(right).val){
return false;
}
right--;
left++;
}
return true;
}
141 环形链表

**核心逻辑:**通过 "快慢指针追击法" 遍历链表 ------ 利用「环形链表中快指针终将追上慢指针,无环链表中快指针会先到末尾」的特性,以快慢双指针从链表头出发,快指针步速 2、慢指针步速 1,逐步遍历验证,无需额外空间且时间复杂度最优,高效判断链表是否有环。
关键步骤:
-
边界初始化:定义快指针 fast = head、慢指针 slow = head(均从链表头起始);
-
快慢指针遍历:循环判断 fast != null 且 fast.next != null(快指针未到链表末尾):
-
快指针步进:fast = fast.next.next(步速 2,快速遍历);
-
慢指针步进:slow = slow.next(步速 1,慢速遍历);
-
追击验证:若 fast == slow(快慢指针相遇),说明链表有环,直接返回 true;
-
-
终止返回:当循环因快指针越界终止时,说明链表无环,返回 false。
java
public boolean hasCycle(ListNode head) {
if (head == null) {
return false;
}
ListNode fast=head;
ListNode slow=head;
while (fast!=null && fast.next!=null){
fast=fast.next.next;
slow=slow.next;
if(fast==slow){
return true;
}
}
return false;
}
142 环形 链表 II

**核心逻辑:**利用快慢指针相遇后,将慢指针重置到链表头,两指针同速遍历终将在环入口相遇的数学特性,分两步操作:先找快慢指针相遇点,再通过同速遍历推导环入口,无需额外空间且时间复杂度最优。
关键步骤:
边界初始化:定义快指针 fast = head、慢指针 slow = head(均从链表头起始);
找快慢指针相遇点,循环判断 fast != null 且 fast.next != null(快指针未到链表末尾):
-
慢指针步进:slow = slow.next(步速 1);
-
快指针步进:fast = fast.next.next(步速 2);
-
相遇验证:若 slow == fast(快慢指针相遇),跳出循环进入阶段 2;
推导环的入口节点:
-
重置慢指针:slow = head(放回链表起始位置);
-
同速遍历验证:循环判断 slow != fast(两指针未相遇),快慢指针均以步速 1 遍历;
终止返回:当 slow == fast 时,该节点即为环的入口节点,返回 slow。
java
public ListNode detectCycle(ListNode head) {
if (head == null || head.next == null) {
return null;
}
// 阶段1:找到相遇点
ListNode slow = head;
ListNode fast = head;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
if (slow == fast) {
break;
}
}
// 阶段2:找环的入口
// 关键操作:把慢指针放回起点,快慢指针都改为一次走1步
slow = head;
while (slow != fast) {
slow = slow.next;
fast = fast.next;
}
return slow;
}
21 合并有序链表

**核心逻辑:**通过 "虚拟头节点 + 双指针归并法" 合并链表 ------ 利用「两个链表本身有序」的特性,以虚拟头节点简化边界处理,双指针分别遍历两个链表,每次选取较小值节点接入结果链表,逐步归并,无需额外空间且时间复杂度最优,高效完成有序链表合并。
关键步骤:
-
边界初始化:定义虚拟头节点 dummy,定义归并指针 current = dummy(指向结果链表的当前末尾);
-
双指针归并遍历:循环判断 list1 != null 且 list2 != null(两个链表均未遍历完):
-
取值对比:若 list1.val <= list2.val,将 list1 接入结果链表(current.next = list1),list1 指针后移;
-
反之,将 list2 接入结果链表(current.next = list2),list2 指针后移;
-
推进结果链表:current = current.next;
-
-
处理剩余节点:循环结束后,将未遍历完的链表剩余部分直接接入结果链表(current.next = list1 或 list2);
-
终止返回:返回虚拟头节点的后继节点(dummy.next),即合并后链表的真实头节点。
java
public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
ListNode dummy = new ListNode(-1);
ListNode current = dummy;
while (list1 != null && list2 != null) {
if (list1.val <= list2.val) {
current.next = list1;
list1 = list1.next;
} else {
current.next = list2;
list2 = list2.next;
}
current = current.next;
}
current.next = (list1 != null) ? list1 : list2;
return dummy.next;
}
2 两数相加

**核心逻辑:**通过 "虚拟头节点 + 逐位累加进位法" 模拟手工加法 ------ 利用「链表逆序存储数字(头为个位)」的特性,以虚拟头节点简化结果链表边界处理,逐位累加两个链表节点值并带上一轮进位,计算当前位值和新进位,逐步构建结果链表,无需额外空间且时间复杂度最优,高效完成链表版两数相加。
关键步骤:
边界初始化:定义虚拟头节点 dummy,结果链表游标指针 curr = dummy,进位变量 carry = 0;
逐位累加遍历:循环判断 l1 != null 或 l2 != null 或 carry != 0(任一链表未遍历完 / 仍有进位):
-
初始化累加和:sum = carry(先带上一轮进位);
-
累加 l1 当前位:若 l1 非空,sum += l1.val,l1 指针后移;
-
累加 l2 当前位:若 l2 非空,sum += l2.val,l2 指针后移;
-
计算进位和当前位:carry = sum / 10(取整得进位),value = sum % 10(取余得位值);
-
构建结果链表:curr.next = new ListNode (value)(当前位接入结果链表),curr 指针后移;
终止返回:循环结束后,返回 dummy.next(虚拟头节点的后继节点,即结果链表真实头节点)。
java
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
ListNode dummy=new ListNode(0);
ListNode curr=dummy;
int carry=0;
int sum=0;
while (l1!=null || l2!=null || carry!=0){
sum=carry;
if(l1!=null){
sum+=l1.val;
l1=l1.next;
}
if(l2!=null){
sum+=l2.val;
l2=l2.next;
}
carry=sum/10;
sum=sum%10;
curr.next=new ListNode(sum);
curr=curr.next;
}
return dummy.next;
}
19 删除链表的倒数第 N 个结点

核心逻辑:通过 "快慢指针间隔定位法" 定位待删节点 ------ 利用「快慢指针拉开 n+1 步间隔后同速遍历,快指针到末尾时慢指针恰好指向待删节点前驱」的特性,以虚拟头节点规避边界问题,无需计算链表长度且时间复杂度最优,高效删除倒数第 N 个节点。
关键步骤:
-
边界初始化:定义虚拟头节点 dummy,dummy.next = head;定义慢指针 slow = dummy、快指针 fast = dummy**(均从虚拟头节点起始)**;
-
快慢指针拉开间隔:循环 n+1 次,让 fast 指针先走 n+1 步(确保慢指针最终指向待删节点的前驱):
- 每次循环执行 fast = fast.next;
-
同速遍历定位前驱:循环判断 fast != null(快指针未到链表末尾):
-
慢指针步进:slow = slow.next(步速 1);
-
快指针步进:fast = fast.next(步速 1);
-
当 fast 为 null 时,slow 恰好指向「倒数第 n+1 个节点」(待删节点的直接前驱);
-
-
删除节点并返回:执行 slow.next = slow.next.next;返回 dummy.next。
java
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode dummy = new ListNode(0);
dummy.next = head;
ListNode slow = dummy;
ListNode fast = dummy;
for (int i = 0; i <= n; i++) {
fast = fast.next;
}
while (fast != null) {
slow = slow.next;
fast = fast.next;
}
slow.next = slow.next.next;
return dummy.next;
}
24 两两交换链表中的节点

**核心逻辑:**通过 "虚拟头节点 + 迭代交换法" 实现节点两两交换 ------ 利用「虚拟头节点简化头节点交换的边界处理」的特性,以虚拟头节点为起始点,每次迭代锁定待交换的两个节点,通过调整指针指向完成局部交换,逐步推进遍历边界,无需额外空间且时间复杂度最优,高效完成两两交换。
关键步骤:
边界初始化:定义虚拟头节点 dummy,dummy.next = head;定义遍历指针 curr = dummy;
迭代交换遍历:循环判断 curr.next != null 且 curr.next.next != null(存在可交换的两个节点):
-
锁定待交换节点:定义 node1 = curr.next(第一个节点)、node2 = curr.next.next(第二个节点);
-
调整指针完成交换:
-
curr.next = node2(前驱节点指向第二个待交换节点,完成交换第一步);
-
node1.next = node2.next(第一个节点指向第二个节点的后继,避免链表断裂);
-
node2.next = node1(第二个节点指向第一个节点,完成交换第二步);
-
准备下一轮交换:curr = curr.next.next;
终止返回:当循环因无足够可交换节点终止时,返回 dummy.next。
java
public ListNode swapPairs(ListNode head) {
ListNode dummy=new ListNode(0,head);
ListNode curr=dummy;
while (curr.next!=null && curr.next.next!=null){
ListNode node1=curr.next;
ListNode node2=curr.next.next;
curr.next=node2;
node1.next=node2.next;
node2.next=node1;
curr=curr.next.next;
}
return dummy.next;
}
138 随机链表的复制

核心逻辑:通过 "三步复制法" 实现深拷贝 ------ 利用链表的链式遍历特性,先在原链表每节点后新增复制节点,再依次设定复制节点的 random 指针,最后拆分原链表与复制链表,通过三次线性遍历完成无哈希表依赖的深拷贝,确保所有指针指向全新节点。
关键步骤:
-
节点插入复制 :遍历原链表,在每个原节点后新建一个复制节点,将原节点值写入新节点,使原链表变为
原节点 -> 复制节点 -> 原节点.next -> ...的交错结构。 -
指定 random 指针:再次遍历链表,定位到复制节点,将其 random 指针指向对应原节点的 random 指针所指向节点的下一个节点(即复制节点),完成 random 指针的深指向。
-
拆分 链表 分离:第三次遍历链表,拆出交错链表中的复制节点,重新构建成新的复制链表,同时恢复原链表的 next 指针,返回复制链表头节点。
java
public Node copyRandomList(Node head) {
if (head == null) {
return null;
}
Node cur = head;
while (cur != null) {
Node copyNode = new Node(cur.val);
copyNode.next = cur.next;
cur.next = copyNode;
cur = copyNode.next;
}
cur = head;
while (cur != null) {
Node copyNode = cur.next;
if (cur.random != null) {
copyNode.random = cur.random.next;
}
cur = copyNode.next;
}
cur = head;
Node copyHead = head.next;
while (cur != null) {
Node copyNode = cur.next;
cur.next = copyNode.next;
if (copyNode.next != null) {
copyNode.next = copyNode.next.next;
}
cur = cur.next;
}
return copyHead;
}
148 排序链表

**核心逻辑:**通过 "归并排序分治归并法" 实现链表排序 ------ 利用「归并排序分而治之 + 链表可通过指针拆分 / 合并」的特性,先以快慢指针找链表中点拆分链表,递归排序左右子链表,再合并两个有序子链表,无需额外空间(递归栈除外)且时间复杂度最优,高效完成链表排序。
关键步骤:
边界初始化:处理空链表 / 单节点链表边界情况(head 为 null 或 head.next 为 null 直接返回 );
找中点拆分链表:定义快慢指针找链表中点的前驱节点(快指针为 head.next):
-
慢指针步进:slow = slow.next(步速 1);
-
快指针步进:fast = fast.next.next(步速 2);
-
拆分操作:midPrev.next = null 切断链表,拆分出左子链表(head)和右子链表(midPrev.next);
-
递归排序子链表:分别递归排序左子链表(sortList (head))和右子链表(sortList (right));
-
合并有序链表:初始化虚拟头节点 dummy,逐位比较两个有序子链表节点值,将较小值节点接入结果链表,拼接剩余节点后返回 dummy.next;
-
终止返回:递归逐层合并完成后,返回最终的有序链表头节点。
java
public ListNode sortList(ListNode head) {
if (head == null || head.next == null) {
return head;
}
ListNode midPrev = findMidPrev(head);
ListNode right = midPrev.next;
midPrev.next = null;
ListNode leftSorted = sortList(head);
ListNode rightSorted = sortList(right);
return mergeTwoSortedLists(leftSorted, rightSorted);
}
private ListNode findMidPrev(ListNode head) {
ListNode slow = head;
ListNode fast = head.next;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
}
return slow;
}
private ListNode mergeTwoSortedLists(ListNode l1, ListNode l2) {
ListNode dummy = new ListNode(0);
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;
}
146 LRU 缓存

核心逻辑: 通过 "哈希表 + 双向链表" 实现 LRU 缓存 ------ 利用哈希表实现 O (1) 时间的键值查找,利用双向链表维护最近使用顺序(头部为最近使用,尾部为最久未使用),每次访问或插入时将节点移到头部,容量不足时删除尾部节点,保证 get 和 put 操作均为 O (1) 平均时间复杂度。
关键步骤:
边界初始化:
-
定义双向链表节点
Node,包含key、value、prev、next; -
初始哈希表
cache(存储键:节点映射)、虚拟头节点head、虚拟尾节点tail、容量capacity; -
连接
head和tail,构建空链表。
get 操作(获取值):
若 key 不存在于 cache,返回 -1;
若存在,取出对应节点 node:
-
将
node从链表中移除; -
将
node插入到链表头部(标记为最近使用); -
返回
node.value。
put 操作(插入 / 更新值):
若 key 已存在:
-
取出节点
node,更新其value; -
将
node从链表中移除,再插入到链表头部;
若 key 不存在:
-
新建节点
newNode,将其插入链表头部; -
将
key → newNode映射存入哈希表; -
若缓存容量超过
capacity:-
删除链表尾部节点(最久未使用);
-
从哈希表中移除该节点的 key 映射。
-
辅助操作(链表维护):
-
removeNode(Node node):从链表中移除指定节点; -
addToHead(Node node):将节点插入到链表头部(head之后); -
removeTail():删除链表尾部节点(tail之前),并返回该节点。
java
class LRUCache {
class Node {
int key;
int value;
Node prev;
Node next;
Node(int key, int value) {
this.key = key;
this.value = value;
}
}
private Map<Integer, Node> cache;
private int capacity;
private Node head;
private Node tail;
private int size;
public LRUCache(int capacity) {
this.capacity = capacity;
this.size = 0;
this.cache = new HashMap<>();
//虚拟头尾节点
this.head = new Node(0, 0);
this.tail = new Node(0, 0);
head.next = tail;
tail.prev = head;
}
public int get(int key) {
Node node = cache.get(key);
if (node == null) {
return -1;
}
// 移动到头部
removeNode(node);
addToHead(node);
return node.value;
}
public void put(int key, int value) {
Node node = cache.get(key);
if (node == null) {
// 新建节点
Node newNode = new Node(key, value);
cache.put(key, newNode);
addToHead(newNode);
size++;
// 容量不足,删除尾部
if (size > capacity) {
Node tailNode = removeTail();
cache.remove(tailNode.key);
size--;
}
} else {
// 更新值并移动到头部
node.value = value;
removeNode(node);
addToHead(node);
}
}
// 移除指定节点
private void removeNode(Node node) {
node.prev.next = node.next;
node.next.prev = node.prev;
}
// 添加到头部
private void addToHead(Node node) {
node.prev = head;
node.next = head.next;
head.next.prev = node;
head.next = node;
}
// 删除尾部节点
private Node removeTail() {
Node tailNode = tail.prev;
removeNode(tailNode);
return tailNode;
}
}
恭喜你学习完成!✿