题目:给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。
例如:
给定一个链表: 1->2->3->4->5, 和 n = 2
当删除了倒数第二个节点后,链表变为 1->2->3->5.
解析:
前面有一题是输出倒数第k个结点。稍微变一点就可以。
1.常规做法
①首先遍历链表,获取链表的长度len;
②删除倒数第n个结点转换成删除顺数第len-n+1个结点;
③此时只要顺数遍历到第len-n结点,将该结点指向第len-n+1结点的下一结点。
public ListNode removeNthFromEnd1(ListNode head, int n) {
if (head == null) return null;
//一般删除结点、交换结点都需要创建一个假头结点接上链表
ListNode tmp = new ListNode(-1);
tmp.next = head;
ListNode p1 = head, p2 = tmp;
int len = 0;
//遍历链表获取链表的长度len
while (p1 != null){
p1 = p1.next;
len++;
}
//倒数第n个结点即为顺数第len-n+1个结点
//遍历到第len-n个结点上(注意p2是从创建的假结点开始遍历)
int k = len-n;
while((k--) > 0){
p2 = p2.next;
}
//将len-n结点接上len-n+1结点的下一结点
p2.next = p2.next.next;
return tmp.next;
}
2.双指针
①定义两个指针p1和p2初始都指向头结点;
②将p2移动到顺数第n+1个结点上,此时p1和p2再同时移动,直到p2移动到null,p1移动到倒数第n个结点上;
③将记录的p1前面的结点接上p1的下个结点;
public ListNode removeNthFromEnd2(ListNode head, int n) {
if (head == null) return null;
ListNode tmp = new ListNode(-1);
tmp.next = head;
//pre前一节点
ListNode p1 = head, p2 = head, pre = tmp;
//p2移动到顺数第n+1个结点
while ((n--) > 0){
p2 = p2.next;
}
//当p2移动到末节点之后,p1移动到倒数第n个节点
while(p2 != null){
pre = p1;//保留p1之前的一个节点
p1 = p1.next;
p2 = p2.next;
}
pre.next = pre.next.next;
return tmp.next;
}