题目描述
19.删除链表中的倒是第N个结点
给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。
示例
给定一个链表: 1->2->3->4->5, 和 n = 2.
当删除了倒数第二个节点后,链表变为 1->2->3->5.
说明
给定的 n 保证是有效的。
进阶
你能尝试使用一趟扫描实现吗?
解题思路
1.单指针+两次遍历
- 先遍历一遍链表,记录链表元素总数 m
- 若要寻找倒数第 N 个元素,即正向找到第 m - n + 1
- 若要删除第 N 个元素,则要找到第 N 个元素的前一个元素 m - n
- 令此时 p->next = p->next->next 即可
注:
- 判断过程中应注意临界条件
- 若 m == 1 时,因为 n 是有效的,则直接返回 NULL
- 若 m == n 即删除首元素时,直接返回 head->next
时间复杂度 O(m + n)
代码如下
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* p = head;
ListNode* q = head;
int m = 0;
while(p != NULL)
{
m++;
p = p->next;
}
if(m == 1)
{
return NULL;
}
if(m == n)
{
return head->next;
}
int k = 1;
while(k < m - n)
{
q = q->next;
k++;
}
q->next = q->next->next;
return head;
}
};
执行结果
2.双指针+一次遍历
借鉴题解思路:
- 设里双指针 rear,front
- 令 rear,front 差 n 时,当 rear == NULL 时,front 恰好位于倒数第 n 的位置
- 因此令 rear,front 差 n + 1 时, front 恰好位于倒数 n + 1 的位置,此时即可删除倒数 n 的元素
- 注意临界条件:删除首元素和链表只有一个结点时,需单独讨论。
时间复杂度: O(n)
代码如下
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* front = head;
ListNode* rear = head;
int k = 0;
int m = 0;
if(head->next == NULL)
{
return NULL;
}
while(rear != NULL)
{
if(k < n + 1)
{
rear = rear->next;
k++;
}
else
{
front = front->next;
rear = rear->next;
}
m++;
}
if(m == n)
{
return head->next;
}
front->next = front->next->next;
return head;
}
};