1. 问题描述
给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。
示例:
给定一个链表: 1->2->3->4->5, 和 n = 2.
当删除了倒数第二个节点后,链表变为 1->2->3->5.
说明:
给定的 n 保证是有效的。
2. 代码实现
方法一:两次遍历
这个问题可以容易地简化成另一个问题:删除从列表开头数起的第 (L - n + 1) 个结点,其中 L 是链表的长度。
所以第一次遍历算出链表长度,第二次遍历找到第 L-n 个结点。
使用哑结点可以处理删除头结点的情况。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode newhead = new ListNode(0);
newhead.next = head;
int length = 0;
ListNode p = head;
while(p != null) {
length++;
p = p.next;
}
length -= n;
p = newhead;
while(length > 0) {
length--;
p = p.next;
}
p.next = p.next.next;
return newhead.next;
}
}
方法二:一次遍历
使用两个指针,第一个指针从链表的开头向前移动 n+1 步,而第二个指针将从链表的开头出发。现在,这两个指针被 n 个结点分开。我们通过同时移动两个指针向前来保持这个恒定的间隔,直到第一个指针到达最后一个结点。此时第二个指针将指向从最后一个结点数起的第 n 个结点。
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode newhead = new ListNode(0);
newhead.next = head;
ListNode first = newhead, second = newhead;
for(int i = 1; i <= n + 1; i++)
first = first.next;
while(first != null) {
first = first.next;
second = second.next;
}
second.next = second.next.next;
return newhead.next;
}
}