给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。
示例:
给定一个链表: 1->2->3->4->5, 和 n = 2.
当删除了倒数第二个节点后,链表变为 1->2->3->5.
说明:
给定的 n 保证是有效的。
进阶:
你能尝试使用一趟扫描实现吗?
Related Topics 链表 双指针
方法1:
第一次遍历获取链表长度;
第二次遍历到length-n-1个位置,移除下一个元素;
需要讨论length-n的值
/**
* 两次遍历
*/
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
int length = getLength(head);
ListNode cur = head;
if(length-n==0){
head = head.next;
return head;
}
else if(length-n==1){
head.next = head.next.next;
return head;
}
for (int i = 0; i < length - n - 1; i++) {
cur = cur.next;
}
cur.next = cur.next.next;
return head;
}
public static int getLength(ListNode head) {
int length = 0;
if (head == null) {
return 0;
}
ListNode cur = head;
while (cur != null) {
length++;
cur = cur.next;
}
return length;
}
}
优化(官方解法):
设置一个哑节点(不携带数据信息)指向头节点,可减少特殊情况讨论
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode dummy = new ListNode(0);
dummy.next = head;
int length = 0;
ListNode first = head;
while (first != null) {
length++;
first = first.next;
}
length -= n;
first = dummy;
while (length > 0) {
length--;
first = first.next;
}
first.next = first.next.next;
return dummy.next;
}
方法2(官方解法):
单次遍历,双指针
first指针与second指针始终保持n个位置;
当first指向链表尾部,second指针也指向倒数n个位置;
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode dummy = new ListNode(0);
dummy.next = head;
ListNode first = dummy;
ListNode second = dummy;
for (int i = 0; i <= n; i++) {
first = first.next;
}
while (first != null) {
first = first.next;
second = second.next;
}
second.next = second.next.next;
return dummy.next;
}
}