题目链接
https://leetcode.cn/problems/remove-nth-node-from-end-of-list/
题解
题解一(Java)
作者:@仲景
最简单的方法就是先遍历一遍链表,统计出链表的长度,求出倒数第n的所在的正数位置
这个方法需要两次遍历,时间复杂度的常数项会大一些,空间复杂度O(1)
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
// 创建一个新头,链到链表的头部
ListNode newHead = new ListNode(-1, head);
// 计算链表一共有多少个节点
ListNode node = head;
int count = 0;
while (node != null) {
count++;
node = node.next;
}
// 得到倒数第n个是正数第几个节点
count = count - n + 1;
// 得到倒数第n个节点的前一个节点
node = newHead;
while (count-- > 1) {
node = node.next;
}
// 删除节点
node.next = node.next.next;
return newHead.next;
}
}
题解二(Java)
作者:@仲景
说到倒数,其实可以想到用栈来解决,因为栈是FILO的结构,所以所有节点压入栈后,其实就是在倒数
这个方法,时间复杂度和题解一基本一样,虽然遍历链表是一次遍历,但是弹栈也算在内的话,和题解一是一样的。
并且需要一个辅助栈,所以空间复杂度是O(n)
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
// 创建一个新头(如果删除的是头结点的话需要一个虚拟节点来表示头结点的前一个节点)
ListNode newHead = new ListNode(-1, head);
// 创建一个辅助栈
LinkedList<ListNode> stack = new LinkedList<ListNode>();
// 遍历链表
ListNode node = newHead;
while (node != null) {
stack.push(node);
node = node.next;
}
// 弹栈,一直弹到倒数第n个节点的前一个节点
while (n-- >= 0) {
node = stack.pop();
}
// 删除节点
node.next = node.next.next;
return newHead.next;
}
}
题解三(Java)
作者:@仲景
使用双指针可以保证绝对只遍历一次链表就可以找到倒数第n个节点的前一个节点
需要注意的是单链表删除某个节点需要找到该节点的前一个节点,所以其实左右指针相差的步数是n+1
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
// 创建一个新头(如果删除的是头结点的话需要一个虚拟节点来表示头结点的前一个节点)
ListNode newHead = new ListNode(-1, head);
ListNode left = newHead;
ListNode right = newHead;
// 右指针向右移动n次,然后左右指针一同移动时,右指针越界,左指针指向倒数第n个节点
// 因为要删除左指针所在节点,所以右指针要多走一步
// 其实左右指针相差的应该是n+1步
while (n-- >= 0) {
right = right.next;
}
// 左右指针同时移动,直到右指针越界
while (right != null) {
left = left.next;
right = right.next;
}
// 此时左指针指向要删除节点的前一个节点
left.next = left.next.next;
return newHead.next;
}
}