删除链表的倒数第 N 个结点
LeetCode19
题目描述:
要做的有两件事:一找到要删除的节点,二让这个节点的前面一个节点指向要删除节点的后一个节点
1. 三指针法
这个方法是自己想的有点繁琐。定义三个指针,一个记录要删除的节点,一个记录待删除节点的前一个节点,最后一个用于遍历。对头节点要另外做处理。
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
if(head.next == null) return null;
ListNode cur = head;
ListNode tmp = head; //当前检查的节点
ListNode pre = head; //当前检查的节点的前一个节点
int m = n;
while(tmp != null){
while(n >= 0){
if(cur == null){
if(tmp == head){ //如果被删除节点是头节点
ListNode newHead = head.next;
head.next = null;
return newHead;
}else{
pre.next = tmp.next;
return head;
}
}
cur = cur.next;
n--;
}
pre = tmp;
tmp = tmp.next;
cur = tmp;
n = m;
}
return head;
}
}
2. 利用哑节点优化一下
看了官解之后学到的。一般这种要删除节点,最好定义一个哑结点,让它的下一个节点指向head,这样就不用对头节点做另外的处理。那么上面的代码就可以优化成:
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode dummy = new ListNode(0,head);
ListNode cur = dummy;
ListNode tmp = dummy; //当前检查的节点
ListNode pre = dummy; //当前检查的节点的前一个节点
int m = n;
while(tmp != null){
while(n >= 0){
if(cur == null){ //找到要删除的节点
pre.next = tmp.next;
return dummy.next;
}
cur = cur.next;
n--;
}
pre = tmp;
tmp = tmp.next;
cur = tmp;
n = m;
}
return dummy.next;
}
}
3.继续优化成双指针
定义一个慢指针slow,一个快指针fast,两者初始都指向哑节点,先让fast向前移n步,然后同时移动slow和fast,当fast指向链表尾部时,slow的下一个节点就是要删除的节点。
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode dummy = new ListNode(0,head);
ListNode slow = dummy;
ListNode fast = dummy;
while(n > 0){
fast = fast.next;
n--;
}
while(fast.next != null){
fast = fast.next;
slow = slow.next;
}
slow.next = slow.next.next;
return dummy.next;
}
}
时间复杂度:O(L)
空间复杂度:O(1)