记录Carl哥代码随想录链表相关。
题意:删除链表中等于给定值 val 的所有节点。
示例 1:
输入:head = [1,2,6,3,4,5,6], val = 6
输出:[1,2,3,4,5]
示例 2:
输入:head = [], val = 1
输出:[]
示例 3:
输入:head = [7,7,7,7], val = 7
输出:[]
链表操作有两种形式:
- 直接使用原来的链表进行删除操作
- 设置一个虚拟头节点再进行删除操作
区别在于前者需要额外考虑头节点被删除的情况,而后者不需要。因此,采用设置虚拟头节点的方式。
ListNode dummyHead = new ListNode(0, head); // 虚拟头节点
ListNode current = dummyHead; // 用以遍历链表
while (current.next != null) {
if (current.next.val == val) {
current.next = current.next.next;
} else {
current = current.next;
}
}
return dummyHead.next;
———————————————————————————————————————————
记录 707.设计链表。
多做几次这个题,对于链表基本的增删查操作就熟悉了。
这里仍然采用虚拟头节点的方式。
链表插入节点时,特别需要注意给next赋值的顺序。如下图所示,应该先给新节点F的next赋值:F.next = C.next,再给C节点的next赋值:C.next = F。如果先C.next = F,那么F.next 就无法指向D了。
此外,就是关于遍历链表的指针current的初始值设定,主要是考虑链表第一个节点(不是虚拟头节点,是真实的第一个节点)的情况。查询操作,对于第一个节点,可以直接获取其值,因此可以令current = dummyHead.next;插入操作,需要利用其前一个节点进行插入,对于第一个节点的插入,需要利用虚拟头节点,因此令current = dummyHead。
class ListNode { // 定义链表节点
int val; // 值域
ListNode next; // 指针域
public ListNode() {
}
public ListNode(int val) {
this.val = val;
}
public ListNode(int val, ListNode next) {
this.val = val;
this.next = next;
}
}
class MyLinkedList {
int size; // 链表长度
ListNode dummyHead; // 虚拟头节点
// 构造函数
public MyLinkedList() {
size = 0;
dummyHead = new ListNode(0);
}
// 获取第index个节点的值
public int get(int index) {
if (index < 0 || index > size - 1) // 索引无效,返回-1
return -1;
ListNode current = dummyHead.next; // 考虑边界情况,即index=0时,不进入循环,直接获取头节点的值,因此令current=dummyHead.next
while (index-- > 0) {
current = current.next;
}
return current.val;
}
// 插入头节点
public void addAtHead(int val) {
ListNode newNode = new ListNode(val); // 新节点
ListNode current = dummyHead; // 插入节点时,只能利用其前一个节点进行插入。因此,要插入头节点,要利用虚拟头节点,令current=dummyHead
newNode.next = current.next; // 注意next赋值的顺序,要先给新节点的next赋值
current.next = newNode;
size++;
}
// 末尾插入节点
public void addAtTail(int val) {
ListNode newNode = new ListNode(val);
ListNode current = dummyHead; // 插入节点时,只能利用其前一个节点进行插入。若size=0,要利用虚拟头节点,因此令current=dummyHead
while (current.next != null) { // 末尾节点的标志就是下一个节点为null
current = current.next;
}
current.next = newNode;
size++;
}
// 在第index个节点之前插入节点
public void addAtIndex(int index, int val) {
if (index > size) // 大于链表长度,不插入
return;
if (index < 0) // <0,在头部插入
index = 0;
ListNode newNode = new ListNode(val);
ListNode current = dummyHead; // 插入节点时,只能利用其前一个节点进行插入。若index=0,要利用虚拟头节点,因此令current=dummyHead
while (index-- > 0) {
current = current.next;
}
newNode.next = current.next;
current.next = newNode;
size++;
}
// 删除第index个节点
public void deleteAtIndex(int index) {
if (index < 0 || index > size - 1) // 无效索引,不删除
return;
ListNode current = dummyHead;
while (index-- > 0) {
current = current.next;
}
current.next = current.next.next;
size--;
}
}