第一题
leetcode 203.移除链表元素
给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 。
public ListNode removeElements(ListNode head, int val) {
ListNode temp = new ListNode(-1,head);//定义一个前置节点,这样可以控制第一节点的删除
ListNode pre = temp;
ListNode cur = head;
while (cur != null){
if (cur.val == val){
pre.next = cur.next;//如果相等,则相当于当前节点的上一节点和下一节点直接相链接
} else {
pre = cur;//不相等,则移动上一节点至当前节点
}
cur = cur.next;//移动当前节点
}
return temp.next;
}
- 需要注意的点在于,第一个节点的删除,所以这里使用了虚节点的概念,设置了一个前置节点,在原链表的前面新增一个节点,这样我们就可以通过连接新链表的第一个节点和第三个节点,实现删除第三个节点的操作。删除其他节点的操作也是一样,通过定位到需要删除的节点的前一个节点和后一个节点来达到目的。
第二题
leetcode 707.设计链表
设计链表的实现。您可以选择使用单链表或双链表。单链表中的节点应该具有两个属性:val 和 next。val 是当前节点的值,next 是指向下一个节点的指针/引用。如果要使用双向链表,则还需要一个属性 prev 以指示链表中的上一个节点。假设链表中的所有节点都是 0-index 的。
在链表类中实现这些功能:
- get(index):获取链表中第 index 个节点的值。如果索引无效,则返回-1。
- addAtHead(val):在链表的第一个元素之前添加一个值为 val 的节点。插入后,新节点将成为链表的第一个节点。
- addAtTail(val):将值为 val 的节点追加到链表的最后一个元素。
- addAtIndex(index,val):在链表中的第 index 个节点之前添加值为 val 的节点。如果 index 等于链表的长度,则该节点将附加到链表的末尾。如果 index 大于链表长度,则不会插入节点。如果index小于0,则在头部插入节点。
- deleteAtIndex(index):如果索引 index 有效,则删除链表中的第 index 个节点。
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/design-linked-list
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
public class MyLinkedList {
ListNode rt;//定义单链表
int size;//定义链表长度
public MyLinkedList() {
rt = new ListNode(0);//虚节点,便于处理第一节点可能被删除的场景
size = 0;//起始定义0
}
//获取任意位置的节点值
public int get(int index) {
if (index < 0 || index >= size) {//判断获取的位置是否符合要求
return -1;
}
ListNode cur = rt;
while (index >= 0) {//移动链表节点
index--;
cur = cur.next;
}
return cur.val;
}
public void addAtHead(int val) {
addAtIndex(0, val);//新增到头节点
}
public void addAtTail(int val) {
addAtIndex(size, val);//新增到末尾节点
}
public void addAtIndex(int index, int val) {
if (index > size) {//根据题意要求,超过size,则 不做处理
return;
}
if (index < 0) { //根据题意要求,小于0,则插入到第一个节点前
index = 0;
}
size++;//维护size
ListNode cur = rt;
while (index > 0) {//移动链表节点
index--;
cur = cur.next;
}
ListNode newNode = new ListNode(val);
newNode.next = cur.next;
cur.next = newNode;//将新增的节点放入链表
}
public void deleteAtIndex(int index) {
if (index >= size || index < 0) {
return;
}
size--;
if (index == 0) {//如果为0,则直接等同于头节点移动到下一个节点
rt = rt.next;
return;
}
ListNode cur= rt;
for (int i = 0; i < index ; i++) {//移动链表
cur= cur.next;
}
cur.next = cur.next.next;//连接前一个节点和下一节点,达到删除的目的
}
}
- 注意点和上一题一样,注意到初始化的时候new ListNode(0),设置了一个虚节点,也是为了方便于原链表的第一个节点的删除和新增的操作。
- 新增链表节点和删除节点都是类似的链表操作。
- 新增节点 : 分解前一个节点和要新增位置处的节点,先分开,将新增的节点,放入中间,连接起来。
- 删除节点:将需要删除节点的前一个节点和后一个节点连接。
第三题
leetcode 206. 反转链表
给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。
public ListNode reverseList(ListNode head) {
ListNode prev = null;
while (head != null) {
ListNode next = head.next;//保存下一个节点的位置
head.next = prev;//将右边的节点连接至左边
prev = head;//移动prev至左边头节点的位置,保证prev是左边的头节点
head = next;//head,移动到下一节点的位置,保证head是右边的头节点
}
return prev;//最后结果是右边链表完全被左边吸收,返回左边链表的头节点prev
}
关键点在于逐步分解和反转节点;
- 1 -> 2 ->3 ->4 -> 5
- 第一步:1 <- 2 3-> 4 -> 5
- 第二步:1 <- 2 <- 3 4 -> 5
- 第三步:1 <- 2 <- 3 <- 4 5
- 第四步:1 <- 2 <- 3 <- 4 <- 5
看上面的步骤可知,我们需要保存两个节点,第一个是左边的头节点,第二个是右边的头节点。然后我们每一步除了保存两个节点外,还需要将右边链表的一个节点连接到左边的链表,并且移动节点的位置。
总结
- 虚节点的使用
- 链表的处理