开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第4天,点击查看活动详情
LeetCode 19. Remove Nth Node From End of List
给你一个链表,删除链表的倒数第 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]
提示:
- 链表中结点的数目为
sz 1 <= sz <= 300 <= Node.val <= 1001 <= n <= szC++ 代码 /**
- Definition for singly-linked list.
- struct ListNode {
-
int val; -
ListNode *next; -
ListNode(int x) : val(x), next(NULL) {} - };
进阶: 你能尝试使用一趟扫描实现吗?
算法1
(两次遍历)
第一次遍历求出链表长度。
第二次遍历删掉指定结点。
注意删除头结点的特殊情况。
时间复杂度
遍历两次链表,故空间复杂度为 O(L)。
空间复杂度
仅需要定义常数个指针变量,故空间复杂度为 O(1)。
ac代码
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
int len = 0;
for (ListNode *cur = head; cur != NULL; cur = cur -> next)
len++;
if (len == n)
return head -> next;
int cnt = 0;
for (ListNode *cur = head; cur != NULL; cur = cur -> next) {
cnt++;
if (cnt == len - n) {
cur -> next = cur -> next -> next;
break;
}
}
return head;
}
};
算法2
(一次遍历)
在头部之前添加保护结点。
设置两个指针 first 和 second,均指向保护结点。
first 指针先向后移动 n+1 个结点。
然后 first 和 second 指针同时向后移动,直到 first 指针指向空,此时 second 结点指向的下一个结点需要删除。
解释:始终保持两个指针之间间隔 n 个结点,在 first 到达终点时,second 的下一个结点就是从结尾数第 n个 结点。
时间复杂度
遍历两次链表,故空间复杂度为 O(L)。
空间复杂度
仅需要定义常数个指针变量,故空间复杂度为 O(1)。
ac 代码:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* ext_head = new ListNode(0);
ext_head -> next = head;
ListNode* first = ext_head;
ListNode* second = ext_head;
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 ext_head -> next;
}
};