文档讲解: 代码随想录
视频讲解: 《代码随想录》算法公开课-跟着Carl学算法
链表理论基础
链表的类型
-
单链表中每个节点由两部分组成:当前节点的值和指向下一个节点的链接(存放下一个节点的地址)。因此虽然链表中的节点在内存中不是连续分布的,但我们可以通过每个节点的链接即可向后查询。
-
双链表:单链表每个节点只有指向下一个节点的链接,而双链表每个节点有两个链接:一个是向后的节点链接,一个是向前的节点链接。
-
循环链表:链表首尾相连(尾节点链接指向首节点)
链表的增删操作
以单链表为例, 若删除下图中间节点,我们只需将它前一个节点的链接指向它下一个节点即可删除当前节点,同时对于Java有自己的内存回收机制,该节点不需要我们手动释放。
如果想要在中间节点的前面添加额外的节点,与删除类似操作,如图所示:
LeetCode203.移除链表元素
题目链接:203.移除链表元素
我们在删除节点时都是通过前一个节点的链接来移除当前节点,那我们思考一个问题:此时想要删除头节点,但是头节点之前并没有节点(当前举例为单链表),那我们该如何删除?下面讨论两种删除头节点方式:
1. 直接使用原来的链表进行删除操作: 我们只需要将链表的head向后移动一位,即可从链表中移除一个头节点。但这种方式缺点也比较明显,由于移除头节点和移除其他节点操作方式不一样,所以需要额外设计一段代码来单独处理头节点。
class Solution {
public ListNode removeElements(ListNode head, int val) {
// 确保头节点不为空
if (head == null) {
return head;
}
// 1.当前头节点为所要删除的节点 将head指向下一位
while (head != null && head.val == val) {
head = head.next;
}
// 2.当前头节点不是所要删除的节点 后续判断其他节点,删除等于val值的节点
ListNode curr = head;
while (curr != null && curr.next != null) {
if (curr.next.val == val) {
curr.next = curr.next.next;
} else {
curr = curr.next;
}
}
return head;
}
}
2. 在当前头节点之前再设置一个虚拟头节点进行删除操作(更推荐): 当前头节点由我们创建的虚拟节点所链接,所以在删除头节点时和删除其他节点操作是一样的,不需要额外操作即可相统一。
class Solution {
public ListNode removeElements(ListNode head, int val) {
// 确保头节点不为空
if (head == null) {
return head;
}
// 头节点前设置虚拟节点
ListNode dummy = new ListNode(-1, head);
ListNode curr = dummy; // 当前节点为虚拟节点,方便后续操作
while (curr.next != null) {
if (curr.next.val == val) {
curr.next = curr.next.next;
} else {
curr = curr.next;
}
}
// 返回虚拟节点下一个节点作为新链表的头节点
return dummy.next;
}
}