LeetCode 19:删除链表的倒数第 N 个结点
方 法 一 : 普 通 算 法 \color{pink}{方法一:普通算法} 方法一:普通算法
(1)先遍历链表,统计链表的结点个数
(2)再次遍历链表,控制遍历到要删除的结点的前一个结点
(3)将待删除结点的前一个结点的后继指针指向待删除结点的后继
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
//创建了一个头结点,定义一个指向头节点的指针
ListNode node = new ListNode(0, head);
ListNode q = node;
//设置计数器
int count = 0;
//循环遍历链表
while(head != null){
count++;
head = head.next;
}
//找到要删除的结点
for(int i = 1; i < count - n + 1; i++){
q = q.next;
}
//删除对应结点
q.next = q.next.next;
//定义一个指向链表第一个结点的指针
ListNode res = node.next;
return res;
}
}
方 法 二 : 双 指 针 \color{pink}{方法二:双指针} 方法二:双指针
(1)创建两个指针,一个指向头结点,一个指向第一个结点
(2)根据 n,将其种一个指针初始化,让两个指针之间的间隔为n + 1
(3)通过已经初始化的指针来遍历链表,当遍历结束时,另一个指针就找到了待删除结点的前驱结点
(4)将待删除结点的前一个结点的后继指针指向待删除结点的后继
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
//创建一个头结点
ListNode node = new ListNode(0, head);
//创建两个指针
ListNode right = head;
ListNode left = node;
//初始化right指针的位置
for (int i = 0; i < n; ++i) {
right = right.next;
}
//遍历链表
while (right != null) {
right = right.next;
left = left.next;
}
//删除结点
left.next = left.next.next;
//返回链表的指针
ListNode ans = node.next;
return ans;
}
}
- 可能有人会发现了,为什么不直接把间隔设置为n呢?这样不是更方便?
(1)如果将两个指针都指向了head 或 node
(2)通过循环就能将两个指针的距离控制为n
(3)但是在遍历链表的时候就会出现问题
如果以
right != null
作为循环条件,就会导致left指针的位置指向了待删除的结点,这样很明显就违背了我们的意愿
如果以right.next != null
作为循环条件,那么会出现空指针异常的问题。如果链表只有一个元素,且 n = 1, 那么在第一次移动 right指针之后,right 已经变为了null
null -> next
在Java中是不允许的