几道链表经典算法题

一、移除链表元素

(Leetcode 203)

1.1 题目
1.2 解题思路

思路一:可以遍历原来的链表,将值为val的节点释放掉。

可以定义一个指针变量pcur,让它从头节点开始遍历链表,如果节点存储的数据值不为val,就将这个值尾插到新链表中。由于我们要把删除的节点的前后两个节点连起来,所以我们还要定义变量prev来标记pcur前面的那个节点。

思路二:可以找值不为val的节点,尾插到新链表中。

由于思路二比较简洁,我们按照思路二来进行代码实现。

1.3 代码实现

首先我们创建两个结构体指针newHead和newTail,分别代表新链表的头节点和尾结点。把它们先都置为空,就相当于创建好了一个新的链表。

接着我们创建一个指针变量pcur来遍历原来链表中的所有节点,判断该节点存储的数据不为空时就将这个节点插入新链表中。

注意此时新链表可能为空,为空的情况需要拿出来特别处理一下:只需让newHead和newTail都指向pcur所在的这个节点即可。

不为空,我们就让newtail的next指向pcur所在的节点,相当于把这个节点尾插到了新链表中。

完成判断和尾插之后我们让pcur沿着原链表往后走一个节点。遍历了所有元素后,即pcur为空的时候,循环结束。

但此时还需要注意,如果原链表的最后一个节点存储的数据恰好是需要被删除的,那么newTail的next仍然指向这个节点,也就是新链表中包括了这个节点。为了避免这种情况,我们需要在遍历结束后把newTail的next置为空。

cpp 复制代码
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */

 typedef struct ListNode ListNode;
struct ListNode* removeElements(struct ListNode* head, int val)
{
    //创建一个空链表
    ListNode* newHead,*newTail;
    newHead = newTail = NULL;
   
    //遍历原链表
    ListNode* pcur = head;
    while(pcur)
    {
        //找值不为value的节点,尾插到新链表中
        if(pcur->val != val)
        {
            //链表为空
            if(newHead == NULL)
            {
                newHead = newTail = pcur;
            }
           else
            {
                //链表不为空
                newTail->next = pcur;
                newTail = newTail->next;
            }
        }
        pcur = pcur->next;
    }
    if(newTail)
     newTail->next = NULL;
    return newHead;
}

二、反转链表

(Leetcode 206)

2.1 题目
2.2 解题思路

思路一: 创建新链表,将原链表中的节点拿过来头插。比较麻烦。

思路二:用三个指针变量解决问题。

首先创建三个指针n1、n2和n3,n1先置为空,n2指向头结点,n3指向第二个节点。

此时我们让n2的next指针不再指向n3,而是指向n1。

然后我们让n1、n2、n3都往后走一个节点。

此后再重复以上的步骤,直到完成链表的反转。

2.3 代码实现

按照上述思路,代码写起来顺理成章。需要注意的是,如果原链表为空,定义n3的过程会涉及对空指针的解引用。为了避免,我们要特别处理链表为空的情况:此时直接返回head即可。

以及,我们让n3向后移动的时候,如果n3已经走到链表末尾,也会导致对空指针的解引用。那我们就加个判断,确保n3的next指针不为空再让n3向后移动。

cpp 复制代码
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
 typedef struct ListNode ListNode;
struct ListNode* reverseList(struct ListNode* head)
{
   //判空
   if(head == NULL)
   {
    return head;
   }
   //创建三个指针
   ListNode*n1,*n2,*n3;
   n1 = NULL,n2 = head,n3 = n2->next;
   while(n2)
   {
    n2->next = n1;
    n1 = n2;
    n2 = n3;
    if(n3)
        n3 = n3->next;
   }
   return n1;
}

三、链表的中间节点

(Leetcode 876)

3.1 题目

3.2 解题思路

思路一:遍历节点,创建变量count来记节点数,返回count/2节点的next节点。

思路二(快慢指针):创建两个指针变量slow和fast,刚开始让两个指针都指向头节点,让后让两个指针以不同的速度沿着链表向前移动,slow每移动一个节点,fast移动两个节点。当fast指针为空(链表节点个数为偶数)或者fast->next为空(链表节点个数为奇数)时,slow指针指向的节点就恰好是所要求的中间节点。

cpp 复制代码
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
 typedef struct ListNode ListNode;
struct ListNode* middleNode(struct ListNode* head)
{
    //创建快慢指针
    ListNode* slow = head;
    ListNode* fast = head;
    while(fast && fast->next)
    {
        slow = slow->next;
        fast = fast->next->next;
        //此时slow正好指向中间节点
    }
    return slow;
}

此处注意,while括号中的两个条件顺序不能交换。因为如果链表节点个数为偶数,最后一次fast会直接指向空,此时对fast进行解引用会报错。目前顺序下,如果fast为空,fast->next会被短路掉,不会执行,也就不会报错。

END

相关推荐
雪碧聊技术27 分钟前
上午题_算法
算法·软考·软件设计师
naturerun1 小时前
从数组中删除元素的算法
数据结构·c++·算法
斯内科2 小时前
四胞胎素数:找出‌个位数分别是 1、3、7、9‌,且‌十位及更高位数字完全相同‌的质数,例如 11、13、17、19
算法·质数·素数·四胞胎素数
Hello.Reader2 小时前
算法基础(十二)——主方法:快速求解常见递归式
算法
小O的算法实验室3 小时前
2026年IEEE TITS,面向按需外卖配送调度的特定问题知识与基于学习元启发式算法,深度解析+性能实测
算法·论文复现·智能算法·智能算法改进
加勒比海带663 小时前
目标检测算法——农林行业数据集汇总附下载链接【Plant】
大数据·图像处理·人工智能·算法·目标检测
洛水水3 小时前
【力扣100题】23. 螺旋矩阵
算法·leetcode·矩阵
瑶池酒剑仙3 小时前
C++类和对象完全指南:从封装继承多态到内存布局的面向对象宝典(雨夜论道)
c语言·开发语言·c++·visual studio
三品吉他手会点灯3 小时前
C语言学习笔记 - 27.C编程预备计算机专业知识 - 什么是字节
c语言·开发语言·笔记·学习