目录
题目
题目要求
示例
解答
方法一、
自己写
实现思路
先从头遍历单链表,找到第一个值不为val的结点,将该结点设为要返回的结点start。然后再次遍历单链表,通过判断curr的下一个结点的值是否为val,如果是的话,就直接将curr的下一个结点删除。最后返回判断好的结点start。
时间复杂度和空间复杂度
时间复杂度:O(N)
空间复杂度:O(1)
代码
c
struct ListNode* removeElements(struct ListNode* head, int val){
if(head==NULL)
{
return NULL;
}
struct ListNode* start = head;
struct ListNode* curr = head;
while(start!=NULL&&start->val==val)
{
start=start->next;
}
while(curr->next!=NULL)
{
if(curr->next->val==val)
{
struct ListNode* del = curr->next;
curr->next = curr->next->next;
free(del);
}
else
{
curr=curr->next;
}
}
return start;
}
方法二、
双指针法
实现思路
设置一个prev指针和curr指针,prev指针用来标记当前访问结点的前一个结点,这样才方便删除结点。当头结点为要删除的结点时,需要特别处理,即需要将head指针向后移动一位,然后删除原先的头节点。
时间复杂度和空间复杂度
时间复杂度:O(N)
空间复杂度:O(1)
代码
c
struct ListNode* removeElements(struct ListNode* head, int val){
struct ListNode* prev = NULL;
struct ListNode* curr = head;
while(curr!=NULL)
{
if(curr->val==val)
{
if(curr==head) //当头结点为要删除的结点时,将头结点移动
{
head=head->next;
free(curr);
curr=head;
}
else
{
prev->next = curr->next;
free(curr);
curr=prev->next;
}
}
else
{
prev = curr;
curr=curr->next;
}
}
return head;
}
方法三、
双链表法
实现思路
当遍历单链表时,遇到结点的值和val不相等时,就将该结点采用尾插法插入到另一个空的单链表中,当遇到结点的值和val的值相等时,就删除该结点,即释放该结点的空间。
时间复杂度和空间复杂度
时间复杂度:O(N)
空间复杂度:O(1)
代码
c
struct ListNode* removeElements(struct ListNode* head, int val){
if(head==NULL)
{
return NULL;
}
struct ListNode* tail = NULL;
struct ListNode* curr = head;
head = NULL; //当结点都为val结点时,此时返回NULL,所以需要将head置为NULL,不然head指向的是已经被释放的结点,此时为野指针。
while(curr!=NULL)
{
if(curr->val!=val)
{
if(tail==NULL) //当tail第一次赋值时,就直接将tail指向这个结点
{
tail = curr;
head = tail; //此时该结点为目标结点的头结点,将head指向该头结点
}
else
{
tail->next = curr;
tail = tail->next;
}
curr = curr->next;
}
else
{
struct ListNode* del = curr;
curr=curr->next;
free(del);
}
}
if(tail!=NULL) //当全都为val结点时,此时tail为NULL,执行NULL->next会出错,所以需要判断
{
tail->next = NULL; //当到最后一个结点时,将最后一个结点的next指针域置为NULL,
}
return head;
}
方法四、
带哨兵的双链表法
实现思路
和第三个方法类似,就是刚开始申请了一个哨兵点,即一个不存数据的头结点,这样就不需要再判断是不是第一次给tail赋值时了,
时间复杂度和空间复杂度
时间复杂度:O(N)
空间复杂度:O(1)
代码
c
struct ListNode* removeElements(struct ListNode* head, int val){
if(head==NULL)
{
return NULL;
}
struct ListNode* tail = NULL;
struct ListNode* curr = head;
//设置哨兵,哨兵位的头结点
head = tail = (struct ListNode*)malloc(sizeof(struct ListNode));
tail->next = NULL;
while(curr!=NULL)
{
if(curr->val!=val)
{ //有了哨兵位,就不需要再判断tail为NULL了
tail->next = curr;
tail = tail->next;
curr = curr->next;
}
else
{
struct ListNode* del = curr;
curr=curr->next;
free(del);
}
}
if(tail!=NULL) //当全都为val结点时,此时tail为NULL,执行NULL->next会出错,所以需要判断
{
tail->next=NULL; //当到最后一个结点时,将最后一个结点的next指针域置为NULL,
}
struct ListNode* del = head;
head=head->next;
free(del); //释放哨兵结点的内存
return head;
}