一、环境说明
- 本文是 LeetCode 19题 : 删除链表的倒数第 N 个结点,使用c语言实现
- 使用双指针方法,算法性能较好。
- 测试环境:Visual Studio 2019
二、代码展示
快慢指针
C++
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
auto dummy = new ListNode(-1);
dummy->next = head;
auto r = dummy;
for(int i = 0;i<n+1;i++) r = r->next;
auto l = dummy;
while(r){
l=l->next;
r=r->next;
}
l->next = l->next->next;
return dummy->next;
}
};
C语言
struct ListNode* removeNthFromEnd(struct ListNode* head, int n){
struct ListNode *right =head,*left = head,* temp =NULL;
//left是删除结点的前一个结点,right比left领先n+1步,temp是待删除结点
for(int i = 0;i<n+1;i++){//让right领先n+1步
if(NULL==right){//要删除的是头结点
left = left->next;//删除操作
head->next = NULL;
free(head);//释放头结点
return left;
}
right = right->next;
}
while(right){//right没有走到最右
right = right->next;//right和left一起往后走
left = left->next;
}
temp = left->next;//待删除结点
left->next = temp->next;//删除操作
temp->next = NULL;
free(temp);//释放结点
return head;
}
朴素做法
C++
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
auto dummy = new ListNode(-1);
dummy->next = head;
int m = 0;//包含哑结点的链表长度
for(auto t = dummy;t;t=t->next) m++;
auto t = dummy;
for(int i = 0;i<m-n-1;i++) t = t->next;
t ->next = t->next->next;
return dummy->next;
}
};
三、思路分析
- 使用快慢指针,先让 r i g h t right right 比 l e f t left left 领先 n + 1 n+1 n+1 步,然后 r i g h t right right 和 l e f t left left 一起向右遍历,等 r i g h t right right 走到最后, l e f t − > n e x t left->next left−>next 刚好是倒数第 N N N 个结点。
- 提示,头结点的删除有所不同,删除头结点时, r i g h t right right 走了 n n n 步就已经为 N U L L NULL NULL 了,此时不应该继续遍历,而是让 l e f t = l e f t − > n e x t left=left->next left=left−>next ,并且返回 h e a d head head 。
- 2022 / 11 / 19 2022/11/19 2022/11/19 更新 C + + C++ C++ 做法,使用哑结点,无需特判头结点 。
四、代码分析
- temp是待删除结点,仅仅为了做题,可以不用temp,但是实际工作中,需要养成释放temp的习惯,避免内存泄漏。(C的做法释放了内存,C++没释放内存)
五、AC
六、复杂度分析
- 时间复杂度: O ( m ) O(m) O(m) , m m m 是链表长度, 遍历链表的时间复杂度 O ( m ) O(m) O(m) 。
- 空间复杂度: O ( 1 ) O(1) O(1) , 除若干变量使用的常量级空间,没有使用额外的线性空间。