1. 问题描述
- 给你一个链表,删除链表的倒数第K个结点,并且返回链表的头结点
- 实例1:输入: head = [1,2,3,4,5],n = 2;输出: [1,2,3,5]
- 实例2:输入: head = [1],n = 1;输出: []
- 实例3:输入: head = [1,2],n = 1;输出: [1]
2. 解法
2.1 相隔为N的前后双指针
- 思路:使用前后两个指针,前指针先移动,当移动次数为 N 时再让后指针从头节点开始向后移动,这样前后双指针刚好相隔N,后续前后指针同步向后移动,直至前指针移动到尾节点,后指针指针所处节点便刚好是倒数第N个节点
- 图解:

- 复杂度:
时间复杂度O(n)、空间复杂度O(1)
- Java实现
/**
* 前后指针一次遍历获取链表的倒数第 n个结点,时间复杂度:O(n) 空间复杂度:O(1)
*
* @param head 链表
* @param n 倒数第 N 个结点
* @return 新链表
*/
public static ListNode removeNthFromEnd(ListNode head, int n) {
// 双指针相隔N,进行遍历
ListNode pre = head, after = head, newListNode = new ListNode(0, head)
int index = 0
while (pre.next != null) {
pre = pre.next
index++
if (index > n) {
// 节点当前的位置大于间隔值K时前指针也开始遍历
after = after.next
}
}
// 将后节点的下一个节点指向下下个节点
after.next = after.next.next
return newListNode.next
}
2.2 获取长度遍历两次
- 思路:第一次遍历获取整个链表的长度length、第二次遍历寻找第length-k位置进行删除
- 复杂度:
时间复杂度O(n)、空间复杂度O(1)
- Java实现
private static int getLength(ListNode head) {
int length = 0;
while (head != null) {
head = head.next;
++length;
}
return length;
}
private static ListNode removeNthFromEnd(ListNode head, int n) {
ListNode newListNode = new ListNode(0, head);
ListNode cur = head;
for (int i = 0; i < getLength(head) - n - 1; i++) {
cur = cur.next;
}
cur.next = cur.next.next;
return newListNode.next;
}
2.3 借助栈
- 思路:遍历所有节点先后加入栈,利用栈后进先出的特点,再依次出栈,出的第N个节点即是倒数第N个节点,删除该节点即可
- 复杂度:
时间复杂度O(n)、需要借助栈,空间复杂度O(n)
- Java实现
/**
* 借助栈来获取链表的倒数第 n个结点,时间复杂度:O(n) 空间复杂度:O(1)
*
* @param head 链表
* @param n 倒数第 N 个结点
* @return 新链表
*/
public static ListNode removeNthFromEnd(ListNode head, int n) {
ListNode newListNode = new ListNode(0, head)
// 实现栈有三种类,包括Stack、ArrayDeque以及Stack,ArrayDeque相对效率更优
ArrayDeque<ListNode> stack = new ArrayDeque<>()
while (head != null) {
stack.push(head)
head = head.next
}
for (int i = 0
stack.pop()
}
// 现在栈最上方的节点刚好就是倒数第N+1个节点
ListNode temp = stack.peek()
// 将倒数第N+1个节点的下一个节点指向倒数第N-1个节点即达到了删除倒数第 N 个几点的目的
temp.next = temp.next.next
return newListNode.next
}