给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。
示例:
给定一个链表: 1->2->3->4->5, 和 n = 2.
当删除了倒数第二个节点后,链表变为 1->2->3->5.
说明:
给定的 n 保证是有效的。
(1)方法:笨方法(两遍遍历)
思路:
1,第一次遍历找到给定链表的长度;
2,要删除倒数第n个节点,其实就是让删除length-n+1那个节点,也就是让第length-n节点的下个节点指向length-n+2即可;
注意:为了防止链表只有一个节点,还删除一个节点,可以在链表前面加一个哑结点,避免这种极端情况
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
//笨方法,首先要知道head共有多少个节点,也就是长度
//就是定义一个哑结点让它指向head的头结点,避免极端(只有一个的情况)
ListNode test = new ListNode(0);
test.next = head;
int len = 0;
//定义一个临时链表,接受head的全部改变长度,直到没有,测长度
ListNode temp = head;
while (temp != null) {
len ++;
temp = temp.next;
}
//定义删除节点的前一个节点位置,删除节点为len-n+1;
len = len - n;
temp = test;
while (len > 0) {
temp = temp.next;
len --;
}
temp.next =temp.next.next;
return test.next;
}
}
(2)方法:双指针遍历法
思路:
1,大概思路和上一个方法思路差不多;
2,因为要删除的节点是length-n的下一个节点,所以我们的目的是让第一个指针先走一段,再让第二个指针和第一个指针一起走,直到第一个走完全部,让第二个指针刚好在length-n这个节点;
3,假设第一个指针先走x个节点,那么就会有第二个节点走的节点有length-x个,从第一个节点往后走(也就是其实是从2开始),所以存在关系
1+length-x=length-n; => 得出结论 x = n + 1;第一个指针先走n + 1 步,就可以保证第二个指针停在length - n的位置,也就是让他们的间隔保证为n;
注意:都加了哑结点在前面,防止只存在一个元素情况下的角标越界异常。
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
//避免极端情况,可以定义一个哑结点
ListNode test = new ListNode(0);
test.next = head;
//双指针遍历,
ListNode first = test;
ListNode second = test;
//first先走n个节点
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 test.next;
}
}