题目概述:
给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。
进阶:你能尝试使用一趟扫描实现吗?
示例 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]
算法思路
1. 数组(空间换时间)
- 先遍历结点,将所有的结点放到数组中,并且记下元素的个数
- 普遍情况:待删除的结点在链表中间,则将length - n - 1的元素的next指向改为length - n的next(length为链表长度)
- 边界情况:
- 如果出现链表长度为1或者为空
- 如果删除的位置在链表头,则将头指针指向下一结点
- 如果删除的位置在链表尾
代码实现:
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode[] node = new ListNode[30];
int count = 0;
ListNode temp = head;
while(temp != null){
node[count] = temp;
count++;
temp = temp.next;
}
if(count == n){
return head.next;
}
node[count - n - 1].next = node[count - n].next;
return head;
}
复杂度分析:
- 时间复杂度:O(n),其中n为链表的长度
- 空间复杂度:O(n),存储结点的数组
2. 双指针
- 因为要删除倒数第N个结点,所以可以设置两个指针,一个快指针,一个慢指针
- 快指针先移动N个结点后,设置一个结点prenote用来存储慢指针所指向的结点前一结点,然后慢指针与快指针同时移动
- 当快指针移动到空结点时,左指针所指向的结点为被删除结点,所以直接将prenote的next更新为删除结点的下一结点(即慢指针的下一结点)
代码实现:
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode dummy = new ListNode(0,head);
dummy.next = head;
ListNode slow = dummy;
ListNode fast = dummy;
while(n-- > 0){
fast = fast.next;
}
ListNode preNode = slow;
while(fast != null){
preNode = slow;
slow = slow.next;
fast = fast.next;
}
preNode.next = slow.next;
return dummy.next;
}
复杂度分析:
- 时间复杂度:O(n),其中n为链表的长度
- 空间复杂度:O(1)