1.题目
https://leetcode.cn/problems/remove-linked-list-elements/description/
给你一个链表的头节点
head
和一个整数val
,请你删除链表中所有满足Node.val == val
的节点,并返回 新的头节点 。示例 1:
输入:head = [1,2,6,3,4,5,6], val = 6 输出:[1,2,3,4,5]示例 2:
输入:head = [], val = 1 输出:[]示例 3:
输入:head = [7,7,7,7], val = 7 输出:[]提示:
- 列表中的节点数目在范围
[0, 104]
内1 <= Node.val <= 50
0 <= val <= 50
- 代码模板
/** * Definition for singly-linked list. * struct ListNode { * int val; * struct ListNode *next; * }; */ struct ListNode* removeElements(struct ListNode* head, int val) { }
2.自解
算法:双指针一次遍历
不加思索写出以下代码
struct ListNode* removeElements(struct ListNode* head, int val)
{
if (head==NULL)
return NULL;
struct ListNode* prev=NULL;
struct ListNode* cur=head;
while(cur)
{
if (cur->val!=val)
{
prev=cur;
cur=cur->next;
}
else
{
prev->next=cur->next;
free(cur);
cur=prev->next;
}
}
return head;
}
会发现报错(null pointer)
分析: 当头结点的需要删除时,执行if判断的else部分
else
{
prev->next=cur->next;
free(cur);
cur=prev->next;
}
prev->next为NULL->next,这是非法的
因此需要先判断prev是否为NULL,如果为NULL则头删(注意:头删一定要移动头结点)
if (cur->val!=val)
{
prev=cur;
cur=cur->next;
}
else
{
if (prev==NULL)
{
head=cur->next;
free(cur);
cur=head;
}
else
{
prev->next=cur->next;
free(cur);
cur=prev->next;
}
}
其他注意事项:特殊情况优先判断:是否为空链表
if (head==NULL)
return NULL;
完整代码为:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* removeElements(struct ListNode* head, int val)
{
if (head==NULL)
return NULL;
struct ListNode* prev=NULL;
struct ListNode* cur=head;
while(cur)
{
if (cur->val!=val)
{
prev=cur;
cur=cur->next;
}
else
{
if (prev==NULL)
{
head=cur->next;
free(cur);
cur=head;
}
else
{
prev->next=cur->next;
free(cur);
cur=prev->next;
}
}
}
return head;
}
提交结果:
3.其他解法
尾插算法,需要找尾,因此需要尾指针tail
不加思索写出以下代码
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* removeElements(struct ListNode* head, int val)
{
if (head==NULL)
return NULL;
struct ListNode* newhead=NULL;
struct ListNode* tail=NULL;
struct ListNode* cur=head;
while(cur)
{
if (cur->val!=val)
{
if (tail==NULL)
{
newhead=tail=cur;
}
else
{
tail->next=cur;
tail=tail->next;
}
cur=cur->next;
}
else
{
struct ListNode* next=cur->next;
free(cur);
cur=next;
}
}
return newhead;
}
注意到heap-use-after-free,不可用指针访问已经被释放的内存空间(野指针行为)
在尝试头删,中间删和尾删后,发现尾删出了问题
设原链表为[1,2,3],val=3,画图为
添加对tail的判断,改成下面这样就行
else
{
struct ListNode* next=cur->next;
free(cur);
cur=next;
}
}
if (tail)
tail->next=NULL;
return newhead;
}
完整代码为
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* removeElements(struct ListNode* head, int val)
{
struct ListNode* newhead=NULL;
struct ListNode* tail=NULL;
struct ListNode* cur=head;
while(cur)
{
if (cur->val!=val)
{
if (tail==NULL)
{
newhead=tail=cur;
}
else
{
tail->next=cur;
tail=tail->next;
}
cur=cur->next;
}
else
{
struct ListNode* next=cur->next;
free(cur);
cur=next;
}
}
if (tail)
tail->next=NULL;
return newhead;
}
提交结果: