给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。
示例:
给定一个链表: 1->2->3->4->5, 和 n = 2.
当删除了倒数第二个节点后,链表变为 1->2->3->5.
说明:
给定的 n 保证是有效的。
进阶:
你能尝试使用一趟扫描实现吗?
一次遍历的思想:
使用一个前指针一个后指针,中间间隔的距离为n,那么当后指针指向尾结点的时候(last.next = null
),前指针的后一个结点即为要删除的结点。1->2->3->4->5 删除第三个元素时,last指针先先后走n=3步指向了4(last从head结点开始走),然后让前指针pre和后指针last一起向后走,直到last.next == null
(即last指向了5),此时pre指向结点2,要删除的倒数第三个结点即为pre的下一个结点,只要执行pre.next = pre.next.next
;返回head结点即可。
考虑特殊情况如果要删除的结点为第一个结点,那么n就是链表的长度,此时last先向后移动n步后将变为null。也只有这一种情况(删除头结点)下,last才会变成null,所以判断一下返回 head.next
即可。
一次遍历:
package Solution.ninteen;
import Solution.two.ListNode;
//执行用时 : 2 ms, 在Remove Nth Node From End of List的Java提交中击败了96.87% 的用户
//内存消耗 : 34 MB, 在Remove Nth Node From End of List的Java提交中击败了97.09% 的用户
//一次遍历
public class NthFromEnd2 {
public ListNode removeNthFromEnd(ListNode head, int n) {
if(head ==null ||head.next==null){
return null;
}
ListNode pre,last;
last = head;
pre = head;
for(int i = 0;i<n;i++){
last = last.next;
}
if(last == null){
return head.next;
}
while(last.next!=null){
last = last.next;
pre = pre.next;
}
pre.next = pre.next.next;
return head;
}
}
两次遍历:
package Solution.ninteen;
import Solution.two.ListNode;
//执行用时 : 1 ms, 在Remove Nth Node From End of List的Java提交中击败了99.73% 的用户
//内存消耗 : 37.4 MB, 在Remove Nth Node From End of List的Java提交中击败了68.51% 的用户
//两次遍历
public class removeNthFromEnd {
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
if(head ==null || head.next == null){
return null;
}
int length = 1;
ListNode p = head;
ListNode q = head;
while(p.next!=null){
p = p.next;
length++;
}
if(n==length){
return q.next;
}
for(int i=0;i<length-n-1;i++){
q= q.next;
}
q.next = q.next.next;
return head;
}
}
}