单链表的习题练习(温故而知新)

删除链表节点

LCR 136. 删除链表的节点 - 力扣(LeetCode)

给定单向链表的头指针和一个要删除的节点的值,定义一个函数删除该节点。

返回删除后的链表的头节点。

示例 1:

输入: head = [4,5,1,9], val = 5
输出: [4,1,9]
解释: 给定你链表中值为 5 的第二个节点,那么在调用了你的函数之后,该链表应变为 4 -> 1 -> 9.

示例 2:

输入: head = [4,5,1,9], val = 1
输出: [4,5,9]
解释: 给定你链表中值为 1 的第三个节点,那么在调用了你的函数之后,该链表应变为 4 -> 5 -> 9.

说明:
  • 题目保证链表中节点的值互不相同
  • 若使用 C 或 C++ 语言,你不需要 free 或 delete 被删除的节点

解法:

一、利用双指针:一个用来寻找val的节点,一个用来保存val的上节点

struct ListNode* deleteNode(struct ListNode* head, int val){
// 头节点为待删除的节点
if(head->val == val) {  
        return head->next;
}
//双指针,一个用来寻找等于val的值,一个用来找寻该节点的上一个节点
struct ListNode *pcur=head;
struct ListNode *next=head;
//寻找
while(next!=NULL&&next->val!=val){
    pcur=next;
    next=next->next;
}
//next!=NULL&&next->val!=val
//说明到达最后一个节点或者找到该节点
if(next!=NULL){
    pcur->next=next->next;
}
//上方排除到最后节点的原因
 return head;
}

二、利用数组,哨兵位来保存不为val的值,在创建newnode(新节点),再进行插入

(这里运用尾插即可) 

反转单链表

LCR 024. 反转链表 - 力扣(LeetCode)

给定单链表的头节点 head ,请反转链表,并返回反转后的链表的头节点。

示例 1:

输入:head = [1,2,3,4,5]
输出:[5,4,3,2,1]

示例 2:

输入:head = [1,2]
输出:[2,1]

示例 3:

输入:head = []
输出:[]

提示:

  • 链表中节点的数目范围是 [0, 5000]
  • -5000 <= Node.val <= 5000

解法:

我们可以利用链表的头插

创建一个为NULL的新节点,将原单链表的值在每次插入的前面

struct ListNode* reverseList(struct ListNode* head){
struct ListNode*cur=head;
//创建一个新节点
struct ListNode*newhead=NULL;
//头插
while(cur){
    struct ListNode*next=cur->next;
//将cur节点的下一个节点指向新节点
    cur->next=newhead;
    newhead=cur;
    cur=next;
}
return newhead;
}

之前我们学会了复杂度,请大家计算一下上面代码的时间复杂度

探索数据结构(让数据结构不再成为幻想)-CSDN博客

大家真聪明!!!

复杂度

  • 时间复杂度:O(n)O(n)O(n),其中 nnn 是链表的长度。需要遍历链表一次。

  • 空间复杂度:O(1)O(1)O(1)。

移除链表元素

203. 移除链表元素 - 力扣(LeetCode)

给你一个链表的头节点 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

解法:

首先

我们while循环,条件为pcur->next!=NULL;每次进入就判断一次

 while (pcur->next != NULL) {
     if (pcur->next->val == val) {
         struct ListNode* prev = pcur->next;//创建新节点保存,用来释放该节点
         pcur->next = prev->next;

         free(prev);
         prev = NULL;
     }
     else
//如果不是,就继续寻找遍历
         pcur = pcur->next;
 }

以上我们是否就能解决问题了呢,是否有特殊情况们没有考虑到

特殊情况:

情况一:head =[]    val =1

这种时候我们就要考虑头节点是否为空

    if(head==NULL){
            return head;
    }
情况二:head =[7,7,7,7]   val =7

当头节点为空时,此时我们就要判断了

   //头节点为目标删除的值
        if(head->val==val){
            head=head->next;
            free(pcur);
            pcur=NULL;
            pcur=head;
        }

此时的头节点变为头节点的下一个了,但还是为目标删除节点,所以这里就要使用到循环

while(head!=NULL&&head->val==val){
     //头节点为目标删除的值
        if(head->val==val){
            head=head->next;
            free(pcur);
            pcur=NULL;
            pcur=head;
        }
}

这样我们这些情况就考虑到了!!!

题解

struct ListNode* removeElements(struct ListNode* head, int val) {
    struct ListNode*pcur=head;

while(head!=NULL&&head->val==val){
     //头节点为目标删除的值
        if(head->val==val){
            head=head->next;
            free(pcur);
            pcur=NULL;
            pcur=head;
        }
}
    if(head==NULL){
            return head;
        }
    while(pcur->next!=NULL){
        if(pcur->next->val==val){
            struct ListNode*prev=pcur->next;
            pcur->next=prev->next;
            free(prev);
            prev=NULL;
        }
      else
        pcur=pcur->next;
    }
    return head;
}

返回链表的中间节点

876. 链表的中间结点 - 力扣(LeetCode)

给你单链表的头结点 head ,请你找出并返回链表的中间结点。

如果有两个中间结点,则返回第二个中间结点。

示例 1:

输入:head = [1,2,3,4,5]
输出:[3,4,5]
解释:链表只有一个中间结点,值为 3 。

示例 2:

输入:head = [1,2,3,4,5,6]
输出:[4,5,6]
解释:该链表有两个中间结点,值分别为 3 和 4 ,返回第二个结点。

提示:

  • 链表的结点数范围是 [1, 100]
  • 1 <= Node.val <= 100

解法

第一种:我们可以利用数组,存放每一个值,在进行取中,数组的取中对我们来说轻而易举,这里就不展示了,希望大家自行编写

第二种:利用快慢指针,想必大家经常听到快慢指针的威名了,那就不解释了,直接上代码

struct ListNode* middleNode(struct ListNode* head) {
    struct ListNode * fast=head;//快指针,每次走两步
    struct ListNode * slow=head;//慢指针,每次走一步
while(fast && fast->next){
//当我们了解到了快慢指针,则考虑的重点就是如何结束循环
    fast = fast->next->next;
    slow = slow->next;
}
return slow;
}
  •     struct ListNode * fast=head;//快指针,每次走两步
  •     struct ListNode * slow=head;//慢指针,每次走一步

注:当我们了解到了快慢指针,则考虑的重点就是如何结束循环

这里我们需要画图来解决:

长度为奇数时

此时为fast->next==NULL;

长度为偶数时

此时fast==NULL;

所以条件为两个

  • 此时为fast->next==NULL;
  • 此时fast==NULL;

题解

struct ListNode* middleNode(struct ListNode* head) {
    struct ListNode * fast=head;
    struct ListNode * slow=head;
while(fast && fast->next){
    fast = fast->next->next;
    slow = slow->next;
}
return slow;
}

 试着练习一下吧!!!

  • 28
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值