今天讲解两道链表OJ题目。
1.链表的中间节点
给你单链表的头结点
head
,请你找出并返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点。
示例
输入:head = [1,2,3,4,5]
输出:[3,4,5]
解释:链表只有一个中间结点,值为 3
方法1【 双指针】
时间复杂度 :O(N)
思想:两个指针,faster的速度是slow两倍,则当faster走到结尾时,slow则走到链表中间。
易错:循环条件
cs
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* middleNode(struct ListNode* head)
{
struct ListNode*faster=head;
struct ListNode*slow=head;
while(faster && faster->next)//条件没想到
{
faster=faster->next->next;
slow=slow->next;
}
return slow;
}
2.移除链表元素
给你一个链表的头节点
head
和一个整数val
,请你删除链表中所有满足Node.val == val
的节点,并返回 新的头节点 。
示例
输入:head = [1,2,6,3,4,5,6], val = 6
输出:[1,2,3,4,5]
方法1【三指针--无哨兵位】
时间复杂度:O(N)
思想:三个指正,cur负责对比val,tmp负责存储删除元素的下一个元素地址,prve负责存储删除元素的上一个元素地址
易错:
- 记住prve是cur的前一个元素,那么它从NULL开始
- 循环条件
- 记得处理头节点和尾节点
- 造成野指针的错误❌
cs
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* removeElements(struct ListNode* head, int val)
{
struct ListNode*cur=head;
struct ListNode*prve=NULL;
while(cur)
{
if(cur->val == val)
{
struct ListNode*tmp=cur->next;
free(cur);
if(prve)
{
prve->next=tmp;
}
else
{
head=tmp;
}
cur=tmp;
}
else
{
prve=cur;
cur=cur->next;
}
}
return head;
}
方法2【双指针---无哨兵位】
cs
/**
* 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(newhead == NULL)
{
newhead=tail=cur;
}
else
{
tail->next=cur;
tail=tail->next;
}
cur=cur->next;
}
else
{
struct ListNode*tmp=cur->next;
free(cur);
cur=tmp;
}
if(tail)
{
tail->next=NULL;
}
}
return newhead;
}
//❌改进
那有哨兵位怎么写呢?
当然,这道题还可以联系前面顺序表(移除val)。
代码---------→【唐棣棣 (TSQXG) - Gitee.com】
联系---------→【邮箱:2784139418@qq.com】