[LeetCode]链表相关题目(c语言实现)

news2024/11/24 5:48:19

文章目录

  • LeetCode203. 移除链表元素
  • LeetCode237. 删除链表中的节点
  • LeetCode206. 反转链表Ⅰ
  • LeetCode92. 反转链表 II
    • 思路 1
    • 思路 2
  • LeetCode876. 链表的中间结点
  • 剑指 Offer 22. 链表中倒数第k个节点
  • LeetCode21. 合并两个有序链表
  • LeetCode86. 分隔链表
  • LeetCode234. 回文链表
  • LeetCode160. 相交链表
  • LeetCode141. 环形链表

LeetCode203. 移除链表元素

  • 题目

给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 。OJ链接

  • 思路
    双指针
  1. 定义指针
    newHead : 返回链表的头结点
    tail : 返回链表的尾结点
    cur : 用于顺序遍历链表
  2. 如果有结点的值等于 val , 直接 free
    如果有结点的值不等于 val, 将该结点尾插至返回链表\
  3. 注意不带哨兵位的链表尾插有两种情况: 插入时链表为空 和 插入时链表不为空
  • 实例

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

在这里插入图片描述

  • 代码实现
struct ListNode* removeElements(struct ListNode* head, int val)
{
    struct ListNode* newHead;   //newHead 指向返回链表的头部
    struct ListNode* cur;       //cur 用于访问原链表
    struct ListNode* tail;      //tail 指向返回链表的尾部
    cur = head; 
    newHead = tail = NULL;

    while (cur)
    {
        if (cur->val == val)    //如果结点的值等于val, 直接free
        {
            struct ListNode* del = cur;
            cur = cur->next;
            free(del);
        }
        else
        {
            if (tail == NULL)
            {
                newHead = tail = cur;      
            }
            else
            {
                tail->next = cur;
                tail = tail->next;
            }
            cur = cur->next;
        }
    }
    
    if (tail)
        tail->next = NULL;
    
    return newHead;
}

LeetCode237. 删除链表中的节点

  • 题目

有一个单链表的 head,我们想删除它其中的一个节点 node

给你一个需要删除的节点 node 。你将 无法访问 第一个节点 head

链表的所有值都是 唯一的,并且保证给定的节点 node 不是链表中的最后一个节点。

删除给定的节点。注意,删除节点并不是指从内存中删除它。这里的意思是:

给定节点的值不应该存在于链表中。
链表中的节点数应该减少 1。
node 前面的所有值顺序相同。
node 后面的所有值顺序相同。
OJ链接

  • 思路

将应删除结点的后一个结点的 val 赋值给应删除节点后, 直接删除后面一个节点

  • 实例
    在这里插入图片描述

5结点的 val 修改为 5 下一结点 1 的值, 删除 后一个 1 结点

  • 代码实现
void deleteNode(struct ListNode* node) 
{
    struct ListNode* nodeNext = node->next; //得到后面的结点

    //将后面结点的值赋值到前面一个结点上
    node->val = nodeNext->val;

    //删除后面的结点
    node->next = nodeNext->next;
    free(nodeNext);
}

LeetCode206. 反转链表Ⅰ

  • 题目

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

  • 思路

定义一个链表指针 newHead = NULL, 遍历每个链表结点头插

  • 实例

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

在这里插入图片描述

  • 代码实现
struct ListNode* reverseList(struct ListNode* head)
{
    struct ListNode* newHead;
    struct ListNode* cur;

    newHead = NULL;
    cur = head;

    while (cur)
    {
        //头插
        struct ListNode* curNext = cur->next;
        cur->next = newHead;
        newHead = cur;
        cur = curNext;
    }

    return newHead;
}

LeetCode92. 反转链表 II

  • 题目

给你单链表的头指针 head 和两个整数 leftright ,其中 left <= right 。请你反转从位置 left 到位置 right 的链表节点,返回 反转后的链表 。OJ链接

思路 1

  • 思路
  1. 如果 left == 1, 会改变头结点, 定义哨兵结点 dammyNode 找到头结点
  2. 找到 prev leftNode rightNode succ 四个位置
  3. 截断出 leftNoderightNode 之间的链表
  4. 反转该链表, 并通过 prev succ 链接
  5. 返回 dammyNode->next
  • 实例

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

在这里插入图片描述

  • 代码实现
//反转链表
struct ListNode* reverseList(struct ListNode* head)
{
    struct ListNode* newHead;
    struct ListNode* cur;

    newHead = NULL;
    cur = head;

    while (cur)
    {
        //头插
        struct ListNode* curNext = cur->next;
        cur->next = newHead;
        newHead = cur;
        cur = curNext;
    }

    return newHead;
}

struct ListNode* reverseBetween(struct ListNode* head, int left, int right)
{
    struct ListNode* prev, *leftNode;
    struct ListNode* succ, *rightNode;
    struct ListNode* cur = head;
    int i = 0;
    //使用哨兵结点, 因为头结点可能发生改变
    struct ListNode* dummyNode = (struct ListNode*)malloc(sizeof(struct ListNode));
    dummyNode->val = -1;
    dummyNode->next = head;

    //先找到四个位置
    prev = dummyNode;
    for (i = 0; i < left - 1; i++)  //找到prev的位置
    {
        prev = prev->next;
    }

    leftNode = prev->next;  //找到leftNode的位置

    rightNode = dummyNode;
    for (i = 0; i < right; i++)  //找到leftNode的位置
    {
        rightNode = rightNode->next;
    }

    succ = rightNode->next;  //找到succ的位置

    //反转leftNode 和 rightNode 之间的位置
    rightNode->next = NULL;
    prev->next = NULL;
    reverseList(leftNode);

    //链接
    prev->next = rightNode;
    leftNode->next = succ;

    return dummyNode->next;
}

思路 2

  • 思路
  1. 如果 left == 1, 会改变头结点, 定义哨兵结点 dammyNode 找到头结点
  2. 找到 prev leftNode rightNode succ 四个位置
  3. 依次将 leftNode->next 移动至 prev->next 直至 leftNode->next == succ
  4. 返回 dummyNode->next
  • 实例

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

在这里插入图片描述

  • 代码实现
struct ListNode* reverseBetween(struct ListNode* head, int left, int right)
{
    struct ListNode* prev, *leftNode;
    struct ListNode* succ, *rightNode;
    struct ListNode* cur = head;
    int i = 0;
    //使用哨兵结点, 因为头结点可能发生改变
    struct ListNode* dummyNode = (struct ListNode*)malloc(sizeof(struct ListNode));
    dummyNode->val = -1;
    dummyNode->next = head;

    //先找到四个位置
    prev = dummyNode;
    for (i = 0; i < left - 1; i++)  //找到prev的位置
    {
        prev = prev->next;
    }

    leftNode = prev->next;  //找到leftNode的位置

    rightNode = dummyNode;
    for (i = 0; i < right; i++)  //找到leftNode的位置
    {
        rightNode = rightNode->next;
    }

    succ = rightNode->next;  //找到succ的位置

    while (leftNode->next != succ)  //注意顺序
    {
        struct ListNode* prevNext = prev->next;
        struct ListNode* leftNodeNext = leftNode->next;
        prev->next = leftNodeNext;
        leftNode->next = leftNodeNext->next;
        leftNodeNext->next = prevNext;
    }
    

    return dummyNode->next;
}

LeetCode876. 链表的中间结点

  • 题目

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

  • 要求

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

  • 思路
    快慢指针
  1. 两个指针 slowfast. slow 每次走一步, fast 每次走两步
  2. 若结点个数是奇数个, slow处在中间结点的时候, fast->next 指向 NULL
    若结点个数是偶数个, slow处在中间结点的时候, fast 指向 NULL
  • 实例

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

在这里插入图片描述

  • 代码实现
struct ListNode* middleNode(struct ListNode* head)
{
    struct ListNode* slow;
    struct ListNode* fast;

    slow = fast = head;

    while (fast && fast->next)
    {
        slow = slow->next;
        fast = fast->next->next;
    }

    return slow;
}

剑指 Offer 22. 链表中倒数第k个节点

  • 题目

输入一个链表,输出该链表中倒数第k个节点。为了符合大多数人的习惯,本题从1开始计数,即链表的尾节点是倒数第1个节点。OJ链接

  • 思路
    快慢指针
  1. slowfast 指向头结点
  2. 先将 fast 向后移动 k
  3. slowfast 同时向后直至 fast 指向 NULL
  4. 注意 k 比链表长度还大的处理
  • 实例

给定一个链表: 1->2->3->4->5, 和 k = 2.
返回链表 4->5.

在这里插入图片描述

  • 代码实现
struct ListNode* getKthFromEnd(struct ListNode* head, int k)
{
    struct ListNode* slow = head, *fast = head;

    while (k && fast)
    {
        fast = fast->next;
        k--;
    }

    if (k)
    {
        return NULL;
    }

    while(fast)
    {
        slow = slow->next;
        fast = fast->next;
    }

    return slow;
}

LeetCode21. 合并两个有序链表

  • 题目

将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 OJ链接

  • 思路
    双指针
  1. 创建虚拟结点 dummyNode 和 返回链表的尾结点 tail
  2. 遍历两个链表, 值小的结点尾插至返回链表
  3. 如果有链表还没有遍历完,直接尾插
  4. 返回 dummyNode->next
  • 实例

输入:l1 = [1,2,4], l2 = [1,3,4]
输出:[1,1,2,3,4,4]

在这里插入图片描述

  • 代码实现
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2)
{
    if (list1 == NULL)
        return list2;
    if (list2 == NULL)
        return list1;

    struct ListNode *dummyNode, *tail;  //创建虚拟结点 和 链表尾结点
    dummyNode = (struct ListNode*)malloc(sizeof(struct ListNode));  
    tail = dummyNode;

    while (list1 && list2)
    {
        if (list1->val < list2->val)
        {
            //尾插
            tail->next = list1;
            list1 = list1->next;
            tail = tail->next;
        }
        else
        {
            //尾插
            tail->next = list2;
            list2 = list2->next;
            tail = tail->next;
        }
    }

    //如果链表还没有遍历完,直接尾插
    if (list1)
        tail->next = list1;
    if (list2)
        tail->next = list2;

    struct ListNode* newHead = dummyNode->next;
    free(dummyNode);

    return newHead; 
}

LeetCode86. 分隔链表

  • 题目

给你一个链表的头节点 head 和一个特定值 x ,请你对链表进行分隔,使得所有 小于 x 的节点都出现在 大于或等于 x 的节点之前。OJ链接

  • 要求

你不需要 保留 每个分区中各节点的初始相对位置。

  • 思路
    双指针
  1. 遍历链表, 值小于 val 的结点, 放入 smallHead 指向的链表;值大于等于 val的结点, 放入 largeHead 指向的链表
  2. smallHead 指向的链表尾插 largeHead 指向的链表
  3. 注意最后的 NULL
  4. 会更改头结点, 使用虚拟结点
  • 实例

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

在这里插入图片描述

  • 代码实现
struct ListNode* partition(struct ListNode* head, int x)
{
    if (!head)
        return NULL;

    struct ListNode* cur = head;    //cur 用于遍历链表
    struct ListNode* large = (struct ListNode*)malloc(sizeof(struct ListNode)); 
    struct ListNode* small = (struct ListNode*)malloc(sizeof(struct ListNode)); 
    struct ListNode* largeHead = large; //虚拟结点指向large
    struct ListNode* smallHead = small; //虚拟结点指向small


    //分组
    while (cur)
    {
        if (cur->val < x)   //小于 x 尾插到 small
        {
            //尾插
            small->next = cur;
            small = small->next;
        }
        else                //大于等于 x 尾插到 large
        {
            //尾插
            large->next = cur;
            large = large->next;
        }

        cur = cur->next;
    }

    //两链表链接
    large->next = NULL;
    small->next = largeHead->next;

    return smallHead->next;
}

LeetCode234. 回文链表

  • 题目

给你一个单链表的头节点 head ,请你判断该链表是否为回文链表。如果是,返回 true ;否则,返回 false 。OJ链接

  • 思路
    快慢指针, 反转链表
  1. 使用快慢指针找到链表的中间结点
  2. 反转中间结点之后的链表
  3. 从两边向中间遍历,判断是否全部相等
  • 实例

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

在这里插入图片描述

  • 代码实现
bool isPalindrome(struct ListNode* head)
{   
    //找到中间结点
    struct ListNode* slow = head, *fast = head;

    while (fast && fast->next)
    {
        slow = slow->next;
        fast = fast->next->next;
    }

    //反转中间结点后半部分链表
    struct ListNode* end = NULL;

    while(slow)
    {
        struct ListNode* slowNext = slow->next;
        slow->next = end;
        end = slow;
        slow = slowNext;
    }

    //从头和从尾同时向中间遍历
    struct ListNode* first = head;

    while (end)
    {
        if (end->val != first->val)
        {
            return false;
        }
        end = end->next;
        first = first->next;
    }

    return true;
}

LeetCode160. 相交链表

  • 题目

给你两个单链表的头节点 headAheadB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null 。OJ链接

图示两个链表在节点 c1 开始相交:

在这里插入图片描述

  • 要求

题目数据 保证 整个链式结构中不存在环。
注意,函数返回结果后,链表必须保持其原始结构

  • 思路
  1. 分别遍历两个链表, 记录两个链表的长度, 最后判断尾结点是否一致.不一致直接返回 false.
  2. 长链表先走长度差的步数, 随后同时遍历两个链表, 遇到的第一个相同的结点即为相交点
  • 实例

在这里插入图片描述

在这里插入图片描述

  • 代码实现
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) 
{
    struct ListNode* curA = headA, *curB = headB;
    int lenA = 0;
    int lenB = 0;

    //遍历A
    while (curA->next)
    {
        lenA++;
        curA = curA->next;
    }

    //遍历B
    while (curB->next)
    {
        lenB++;
        curB = curB->next;
    }

    if (curA != curB)
    {
        return NULL;
    }

    //计算差值步, 找出长度长的链表
    int step = abs(lenA-lenB);
    struct ListNode* longNode = headA, *shortNode = headB;

    if (lenB > lenA)
    {
        longNode = headB;
        shortNode = headA;
    }

    //长度长的先走差值步
    while (step)
    {
        longNode = longNode->next;
        step--;
    }

    //同时遍历两链表
    while (longNode)
    {
        if (longNode == shortNode)
        {
            break;
        }
        longNode = longNode->next;
        shortNode = shortNode->next;
    }

    return longNode;
}

LeetCode141. 环形链表

  • 题目

给你一个链表的头节点 head ,判断链表中是否有环。
如果链表中存在环 ,则返回 true 。 否则,返回 false 。OJ链接

  • 思路
    快慢指针
  1. slow 每次走一步, fast 每次走两步
  2. 如果 slow == fast 有环
  3. 如果无环, fast会直接出链表
  • 实例

输入:head = [3,2,0,-4], pos = 1
输出:true
解释:链表中有一个环,其尾部连接到第二个节点。

在这里插入图片描述

  • 代码实现
bool hasCycle(struct ListNode *head) 
{
    struct ListNode* slow = head, *fast = head;

    while (fast && fast->next)
    {
        slow = slow->next;
        fast = fast->next->next;

        if (slow == fast)
        {
            return true;
        }       
    }

    return false;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/825001.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何打造属于自己的个人IP?

在当今信息爆炸的时代&#xff0c;个人 IP 已经成为人们在网络世界中的独特标签。无论是在职场上、创业中&#xff0c;还是在社交生活中&#xff0c;拥有个人 IP 的人都能脱颖而出&#xff0c;吸引更多的关注和机会。那么&#xff0c;如何打造属于自己的个人 IP 呢&#xff1f;…

机器学习和深度学习简述

一、人工智能、机器学习、深度学习的关系 近些年人工智能、机器学习和深度学习的概念十分火热&#xff0c;但很多从业者却很难说清它们之间的关系&#xff0c;外行人更是雾里看花。概括来说&#xff0c;人工智能、机器学习和深度学习覆盖的技术范畴是逐层递减的&#xff0c;三…

华为OD机试真题 JavaScript 实现【名字的漂亮度】【牛客练习题】

目录 一、题目描述二、输入描述三、输出描述四、解题思路五、JavaScript算法源码 华为OD机试 2023B卷题库疯狂收录中&#xff0c;刷题点这里 刷的越多&#xff0c;抽中的概率越大&#xff0c;每一题都有详细的答题思路、详细的代码注释、样例测试&#xff0c;发现新题目&#x…

vue3实现拖拽排序

效果&#xff1a; 实现 <template><div class"box"><divv-for"(item, index) in items":key"item.id"class"item":style"{ order: item.order }":draggable"true"dragstart"onDragStart(in…

redis的安装和配置

一、nosql 二、redis的安装和配置 redis的安装&#xff1a; redis常见配置&#xff1a; 配置文件redis.conf

DP学习第五篇之礼物的最大价值

DP学习第五篇之礼物的最大价值 剑指 Offer 47. 礼物的最大价值 - 力扣&#xff08;LeetCode&#xff09; 一.题目解析 二. 算法原理 状态表示 tips: 经验题目要求。以[i,j]位置为结尾&#xff0c;。。。 dp[i][j]: 到达[i, j]位置时&#xff0c;此时的最大礼物价值 状态转移…

Java版工程行业管理系统源码-专业的工程管理软件- 工程项目各模块及其功能点清单 em

&#xfeff;Java版知识付费源码 Spring CloudSpring BootMybatisuniapp前后端分离实现知识付费平台 提供职业教育、企业培训、知识付费系统搭建服务。系统功能包含&#xff1a;录播课、直播课、题库、营销、公司组织架构、员工入职培训等。 提供私有化部署&#xff0c;免费售…

【css】css隐藏元素

display:none&#xff1a;可以隐藏元素。该元素将被隐藏&#xff0c;并且页面将显示为好像该元素不在其中。visibility:hidden&#xff1a; 可以隐藏元素。但是&#xff0c;该元素仍将占用与之前相同的空间。元素将被隐藏&#xff0c;但仍会影响布局。 代码&#xff1a; <!…

Maya中polygon和transform区别?

In Autodesk Maya, “polygon” and “transform” are two fundamental types of nodes used to represent different aspects of 3D geometry and the transformation of objects in the scene. Polygon (polyMesh): A polygon node, often referred to as a “polyMesh,” r…

Ubuntu开机自启服务systemd.service配置教程(Ubuntu服务)(Linux服务)upstart

文章目录 为什么要将程序配置成服务&#xff1f;1. 自动启动2. 后台运行3. 定时重启4. 简化管理5. 整合系统 版本支持1. Ubuntu 14.04及更早版本&#xff1a;使用upstart作为默认的init系统/etc/rc.local旧版本新版本 2. Ubuntu 15.04到16.04版本&#xff1a;默认使用systemd作…

CTFSHOW php 特性

web89 数组绕过正则 include("flag.php"); highlight_file(__FILE__);if(isset($_GET[num])){$num $_GET[num]; get numif(preg_match("/[0-9]/", $num)){ 是数字 就输出 nodie("no no no!");}if(intval($num)){ 如果是存在整数 输出 flagecho …

算法通关村第四关——如何基于数组(链表)实现栈

栈的基础知识 栈的特征 特征1 栈和队列是比较特殊的线性表&#xff0c;又被称为 访问受限的线性表。栈是很多表达式、符号等运算的基础&#xff0c;也是递归的底层实现&#xff08;递归就是方法自己调用自己&#xff0c;在JVM的虚拟机栈中&#xff0c;一个线程中的栈帧就是…

使用分布式数据库,还需要考虑做分库分表吗?

随着数据存储需求的不断增加&#xff0c;分布式数据库成为了处理大规模数据的一种重要方式。分布式数据库可以将数据分散到多个计算节点上&#xff0c;并利用分布式计算的能力来提高数据处理的效率和可用性。然而&#xff0c;在使用分布式数据库的过程中&#xff0c;是否需要进…

网络安全工具包NST发布38-13644版本

导读开源网络安全工具包NST近日发布了最新版本38-13644。该版本基于Fedora 38构建,使用Linux 6.3.12内核,主要针对软件的维护与功能增强进行了更新。 根据发布公告,新版本通过Docker容器方式重构了OpenVAS和Greenbone漏洞扫描组件,实现了完整的漏洞评估能力。另外,还增强了地理…

微信公众号程序PHP源码 收银台源码 商家PHP源码 微信支付扫码付款 商家收银台

商家收银台-微信支付扫码付款-微信支付收银台-PHP源码 微信公众号程序&#xff0c;必须微信认证服务号&#xff0c;微信支付商家 客户扫码&#xff0c;打开商家定义支付页面&#xff0c;输入金额和对应定义信息&#xff0c;提交微信支付&#xff0c;实现快速付款 支持创建多…

信息系统网络安全整改方案

第1章 项目概述 1.1 项目目标 本方案将通过对公司网络信息系统的安全现状进行分析工作&#xff0c;参照国家信息系统等级保护要求&#xff0c;找出信息系统与安全等级保护要求之间的差距&#xff0c;给出相应的整改意见&#xff0c;推动 XX 企业公司网络信息系统安全整改工作的…

将jar包打入本地maven仓库

1、准备好要入仓的jar包 2、在jar包所在文件夹打开cmd 3、输入如下命令进行打包 mvn install:install-file -DgroupIdcom.netty.common -DartifactIdnetty-common -Dversion1.0-SNAPSHOT -Dpackagingjar -Dfilenetty-common-1.0-SNAPSHOT.jar如下图所示&#xff1a;

TCP连接的状态详解以及故障排查(三)

TCP连接建立三次握手 TCP是一个面向连接的协议&#xff0c;所以在连接双方发送数据之前&#xff0c;都需要首先建立一条连接。 Client连接Server&#xff1a; 当Client端调用socket函数调用时&#xff0c;相当于Client端产生了一个处于Closed状态的套接字。 (1)第一次握手&a…

10.事件流

10.1事件流和两个阶段说明 ●事件流指的是事件完整执行过程中的流动路径 简单来说&#xff1a;捕获阶段是从父到子 冒泡阶段是从子到父 10.2事件捕获 事件捕获概念&#xff1a; 从DOM的根元素开始去执行对应的事件(从外到里) ●事件捕获需要写对应代码才能看到效果 ●代码:…

Java从入门到精通(三)· 基础逻辑

Java从入门到精通&#xff08;三&#xff09; 基础逻辑 一 分支结构 1.if分支 if分支是根据条件的真假来决定执行某段代码。 If 分支的小技巧和常见问题&#xff1a; 2.switch分支 通过比较变量的值来确定执行哪条分支。 switch的使用注意事项&#xff1a; 当存在多个case分…