203. 删除链表中的节点
Remove all elements from a linked list of integers that have value val.
Example:
Input: 1->2->6->3->4->5->6, val = 6
Output: 1->2->3->4->5
删除链表中等于给定值 val 的所有节点。
示例:
输入: 1->2->6->3->4->5->6, val = 6
输出: 1->2->3->4->5
解法一(Iteration):
首先处理链头就遇到待删除元素的情况,直到链头不是待删除元素,接着判断是否为空。若不为空,则判断下一个结点是否为空,不为空就检查其是否是待删除元素,若是则将当前结点的 next 指针指向当前结点 next 的 next 的结点,否则就继续遍历链表。
public ListNode removeElements(ListNode head, int val) {
while (head != null && head.val == val) {
head = head.next;
}
if (head == null)
return null;
ListNode prev = head;
while (prev.next != null) {
if (prev.next.val == val) {
prev.next = prev.next.next;
} else {
prev = prev.next;
}
}
return head;
}
解法二(Virtual Head Node):
解法一的优化,增加一个虚拟的头结点,不需要再对输入的头结点进行判断空和是否是删除元素的特殊处理。
public ListNode removeElements(ListNode head, int val) {
ListNode dummyNode = new ListNode(-1);
dummyNode.next = head;
ListNode prev = dummyNode;
while (prev.next != null) {
if (prev.next.val == val) {
prev.next = prev.next.next;
} else {
prev = prev.next;
}
}
return dummyNode.next;
}
解法三(Recursion):
解法一的递归写法,注意在不删除当前结点的情况下,需要将当前结点指向递归完成后的头结点。
public ListNode removeElements(ListNode head, int val) {
if (head == null)
return null;
ListNode res = removeElements(head.next, val);
if (head.val == val) // 将删除当前结点
return res;
else { // 不删除当前结点
head.next = res;
return head;
}
}
或者
public ListNode removeElements(ListNode head, int val) {
if (head == null) return null;
head.next = removeElements(head.next, val);
return head.val == val ? head.next : head;
}
如果文章里有说得不对的地方请前辈多多指正~ 与君共勉~
19. 删除链表的倒数第N个节点
给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。
示例:
给定一个链表: 1->2->3->4->5, 和 n = 2.
当删除了倒数第二个节点后,链表变为 1->2->3->5.
说明:
给定的 n 保证是有效的。
进阶:
你能尝试使用一趟扫描实现吗?
分析
题目要求一趟遍历删除倒数的第n个节点,我们不知道链表的长度,该如何知道第n个节点是哪个呢。其实可以使用快、慢两个指针来完成这一目标,快指针从链头开始先走n个节点,然后慢指针从链头出发,两者同时向前移动,当快指针到达末尾时,慢指针所在位置就是倒数第n个节点的前一个节点,这时候只要跳过它指向它的下一个节点即可。
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode fast = head;
// 快指针先走 n 步
for (int i = 0 ; i < n ; i ++) {
fast = fast.next;
}
ListNode slow = head;
// 要删除第一个的情况
if (fast == null) {
return head.next;
}
// 当快指针走到结尾时,慢指针就是待删除结点的前一个结点
while (fast.next != null) {
fast = fast.next;
slow = slow.next;
}
slow.next = slow.next.next;
return head;
}
237. 删除链表中的节点
这道题与上一题乍一看都是删除链表中的一个节点,但不同的是这题给的不是整个链表,而是待删除的节点。我们知道要删除一个节点需要它的前驱节点的指针,但是这里是无法得到的,只能想一个变通的方法。所以仔细一想,只要交换给定节点和其下一个节点的内容,然后删除下一个节点,这样不就可以了。
public void deleteNode(ListNode node) {
node.val = node.next.val;
ListNode nextNode = node.next;
node.next = nextNode.next;
nextNode.next = null; // 别忘了置为null,垃圾回收
}