解法1
先遍历一遍计算链表长度,再遍历一遍删除倒数第n个节点
时间复杂度O(n)
但是遍历了两遍链表
解法2
只遍历一遍链表
同样地加上一个虚拟头结点
对应这个链表,要删除的是p,需要找到p前面的一个节点
这时p指向要删除节点的前一个节点,q指向尾节点
然后,将p,q向前挪,使p指向虚拟头结点
由于p到q之间的长度是固定的,所以如果p是虚拟头结点的话,那么q应该是p向后移动n+1次
接下来让p和q同时向前移动,此时p和q之间的距离并不会发生变化
一直到q指向了null,那么p就指向了要删除元素的前一个节点
这样,只遍历了一遍链表,使用两个指针进行辅助
code
public ListNode removeNthFromEnd(ListNode head, int n) {
//虚拟头结点
ListNode dummyHead = new ListNode(0);
dummyHead.next = head;
//声明快慢指针
ListNode slow = dummyHead;
ListNode fast = dummyHead;
//快指针先走n+1步
for(int i=0;i<n+1;i++)
fast = fast.next;
//同时向后移动,直到快指针为null,此时慢指针指向待删除元素的前一个节点
while(fast!=null){
slow = slow.next;
fast = fast.next;
}
//删除节点
slow.next = slow.next.next;
//返回真实头结点
return dummyHead.next;
}
// time O(n)
// space O(1)