【链表】算法题(二) ----- 力扣/牛客

news2024/9/20 14:36:01

一、链表的回文结构

思路:

        找到链表的中间节点,然后逆置链表的后半部分,再一一遍历链表的前半部分和后半部分,判断是是否为回文结构。

快慢指针找到链表的中间节点

        slow指针指向的就是中间节点

逆置链表后半部分

        逆置链表后半部分

遍历链表前半部分和后半部分

        如果left和right指向的数据不相等,就跳出循环,返回false;如果遍历到left或者right为NULL,数据都相等,那么链表具有回文结构,返回true。

这里如果是奇数个节点:

遍历结束后:

class PalindromeList {
public:
    //找链表中间节点
    ListNode* Listmid(ListNode* phead)
    {
        ListNode* fast, *slow;
        fast=slow=phead;
        while(fast && fast->next)
        {
            slow=slow->next;
            fast=fast->next;
        }
        return slow;
    }
    //逆置
    ListNode* reverse(ListNode* phead)
    {
        ListNode* l1,*l2,*l3;
        l1=NULL;
        l2=phead;
        while(l2)
        {
            l3=l2->next;
            l2->next=l1;
            l1=l2;
            l2=l3;
        }
        return l1;
    }
    bool chkPalindrome(ListNode* A) {
        // write code here
        //找到链表中间节点
        ListNode* mid=Listmid(A);
        //逆置后半部分
        ListNode* phead = reverse(mid);
        //比较
        ListNode* left, *right;
        left=A;
        right=phead;
        while(right && left)
        {
            if(right->val!=left->val)
            {
                return false;
            }
            left=left->next;
            right=right->next;
        }
        return true;
    }
};

二、相交链表

判断两个链表是否相交,如果相交就返回相交节点,如果链表不相交,那就返回NULL;

思路:

        先遍历两个链表,记录两个链表的节点个数;再同时遍历两个链表 ,让节点个数多的链表先往前走s(链表的节点个数差);同时遍历两个链表,如果指向链表的指针相等,就返回当前节点;如果遍历链表结束后,都没有相等的节点,那就返回NULL。

typedef struct ListNode ListNode;
struct ListNode* getIntersectionNode(struct ListNode* headA,
                                     struct ListNode* headB) {
    if (headA == NULL) {
        return NULL;
    }
    if (headB == NULL) {
        return NULL;
    }
    int sizeA = 0, sizeB = 0;
    ListNode *l1, *l2;
    l1 = headA;
    l2 = headB;
    while (l1) {
        sizeA++;
        l1 = l1->next;
    }
    while (l2) {
        sizeB++;
        l2 = l2->next;
    }
    ListNode* shortList = headA;
    ListNode* longList = headB;
    int s = abs(sizeA - sizeB);
    if (sizeA > sizeB) {
        shortList = headB;
        longList = headA;
    }
    while (s) {
        s--;
        longList = longList->next;
    }
    while (longList && shortList) {
        if (longList == shortList) {
            return longList;
        }
        longList = longList->next;
        shortList = shortList->next;
    }
    return NULL;
}

三、环形链表1

判断 链表中是否存在环,如果存在就返回true,如果不存在就返回false;

思路:快慢指针

        定义两个指针fast和slow;遍历链表,fast每次向前走两步,slow每次向前走一步,如果链表存在环,fast与slow指针一定会相遇;如果遍历链表,fast或者fast->next为NULL,则链表不存在环。

根据题目所给示例来分析一下:

        首先定义两个指针 fast  slow

        fast向前走两步,slow向前走一步

        fast向前走两步,slow向前走一步

        fast向前走两步,slow向前走一步

此时,fast和slow相遇,证明链表中存在环,返回true。

        如果链表不存在环结构,遍历过程中fast或者fast->next指针会等于NULL,将这个作为结束条件即可。

typedef struct ListNode ListNode;
bool hasCycle(struct ListNode *head) {
    ListNode* fast, *slow;
    fast=slow=head;
    while(fast && fast->next)
    {
        fast=fast->next->next;
        slow=slow->next;
        if(slow == fast)
        {
            return true;
        }
    }
    return false;
}

四、环形链表2

        上面只是让我们判断链表是否带环,这道题让我们返回链表环的起始节点,如果不存在环就返回NULL。

思路:

        使用快慢指针找到快慢指针的相遇节点;再定义两个指针从相遇节点和链表头结点开始遍历,两个指针相遇时的节点就是链表环的起始节点。

根据题目的示例来分析:

        先找到链表快慢指针的相遇节点:

        定义两个指针从链表头部和相遇节点开始遍历链表

        遍历链表直到两个指针相遇

        两个指针相遇,此时指针指向的节点就是链表环的起始节点。

typedef struct ListNode ListNode;
ListNode* hasCycle(struct ListNode *head) {
    ListNode* fast, *slow;
    fast=slow=head;
    while(fast && fast->next)
    {
        fast=fast->next->next;
        slow=slow->next;
        if(slow == fast)
        {
            return slow;
        }
    }
    return NULL;
}
struct ListNode *detectCycle(struct ListNode *head) {
    //找到快慢指针相遇节点
    ListNode* pos=hasCycle(head);
    if(pos==NULL)
    {
        return NULL;
    }
    //从头结点和相遇节点开始遍历
    ListNode* ptail=head;
    while(1)
    {
        if(pos==ptail)
        {
            return pos;
        }
        pos=pos->next;
        ptail=ptail->next;
    }
}

五、随机链表的复制

这里题目上提到了一个深拷贝

  思路:

        先在原链表的基础上创建节点,形成新的链表,再给链表节点的random指针赋值,最后断开新链表和原链表的连接即可。

        深拷贝原链表

        拷贝过后

        给random指针赋值

        断开新链表和原链表之前的连接

这样就深拷贝了原链表,返回新链表的头节点即可。

typedef struct Node Node;
// 创建节点
Node* BuyNode(int x) {
    Node* newnode = (Node*)malloc(sizeof(Node));
    newnode->next = newnode->random = NULL;
    newnode->val = x;
    return newnode;
}
// 深拷贝
void CopyList(Node** head) {
    Node* ptail = *head;
    Node* next = NULL;
    while (ptail) {
        next = ptail->next;
        Node* newnode = BuyNode(ptail->val);
        newnode->next = next;
        ptail->next = newnode;
        ptail = next;
    }
}
void Connect(Node** head) {
    Node* ptail = *head;
    Node* copy = (*head)->next;
    while (ptail) {
        copy = ptail->next;
        if (ptail->random)
            copy->random = ptail->random->next;
        ptail = copy->next;
    }
}
struct Node* copyRandomList(struct Node* head) {
    if (head == NULL)
    {
        return NULL;
    } 
    // 深拷贝原链表
    CopyList(&head);
    // 连接random指针
    Connect(&head);
    // 断开链表
    Node* ptail = head;
    Node* newhead = head->next;
    Node* copy = head->next;
    while (ptail->next->next) {
        ptail=copy->next;
        copy->next = copy->next->next;
        copy = copy->next;
    }
    return newhead;
}

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

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

相关文章

【JavaScript 算法】图的遍历:理解图的结构

🔥 个人主页:空白诗 文章目录 一、深度优先搜索(DFS)深度优先搜索的步骤深度优先搜索的JavaScript实现 二、广度优先搜索(BFS)广度优先搜索的步骤 三、应用场景四、总结 图的遍历是图论中的基本操作之一&am…

安卓 mvp 的架构的详细介绍

MVP 架构介绍 MVP(Model-View-Presenter)是一种软件架构模式,常用于构建用户界面(UI)。它将应用程序的逻辑划分为三个部分:Model、View 和 Presenter。MVP 的主要目标是分离视图和业务逻辑,使代…

ECU通讯:CAN总线仿真测试

01.ECU 在软件定义汽车的大背景下,几乎每一个汽车功能都需要依靠ECU(Electronic Control Unit,电子控制单元)来实现:有些功能靠ECU独立实现,有些功能则需要多个ECU联合实现。总体来说,ECU绝大多…

解决SonarQube中Vue项目中deep选择器报错的问题

1. 前言 当使用SonarQube对Vue项目进行代码质量审查时,可能会遭遇因Vue特有的deep选择器(旨在实现样式深度穿透)而触发的错误或警告。由于SonarQube默认并不识别这一Vue特有的语法,这些错误报告可能会成为审查过程中的干扰项。为了…

Mysql sql技巧与优化

1、解决mysql同时更新、查询问题 2、控制查询优化 hint 3、 优化 特定类型的查 优化 COUNT() 查询 使用 近似值 业务能接受近似值的话,使用explain拿到近似值 优化关联查询 优化子查询 4、优化group by和distinct 优化GROUP BY WITH ROLLUP 5、优化 limit分页 其他…

【MySQL-19】一文带你了解存储函数

前言 大家好吖,欢迎来到 YY 滴MySQL系列 ,热烈欢迎! 本章主要内容面向接触过C的老铁 主要内容含: 欢迎订阅 YY滴C专栏!更多干货持续更新!以下是传送门! YY的《C》专栏YY的《C11》专栏YY的《Lin…

Richteck立锜科技电源管理芯片简介及器件选择指南

一、电源管理简介 电源管理组件的选择和应用本身的电源输入和输出条件是高度关联的。 输入电源是交流或直流?需求的输出电压比输入电压高或是低?负载电流多大?系统是否对噪讯非常敏感?也许系统需要的是恒流而不是稳压 (例如 LED…

应届生软件测试面经_一名应届生的软件测试面试题目

1.你为什么选择软件测试行业 因为之前有了解软件测试这个行业,觉得他的发展前景很好, 2.根据你以前的项目经验描述一下软件开发、测试过程,由那些角色负责,你做什么 要有架构师、开发经理、测试经理、程序员、测试员。我在里面…

什么是死锁 , 以及产生的原因详细介绍

死锁 一. 什么是死锁 指的是两个或者两个以上的线程在执行的过程中由于竞争同步锁而产生的一种阻塞现象;如果没有外力的作用,他们将无法继续执行下去,这种情况称之为死锁, 通俗的说死锁产生的原因主要是由于线程的相互等待 , 导致程序无法进行下去 二. 代码阐述 这里我们写…

科技论文在线--适合练习期刊写作和快速发表科技成果论文投稿网站

中国科技论文在线这个平台可以作为练手的一个渠道,至少可以锻炼一下中文写作,或者写一些科研方向的简单综述性文章。当然,如果你的老师期末要求也是交一份科技论文在线的刊载证明的话,这篇文章可以给你提供一些经验。 中国科技论…

数据结构 - 队列(精简介绍)

文章目录 单端队列单端队列操作:Queue实现 双端队列双端队列操作:Deque实现 循环队列循环队列手动实现 优先级队列Q 不断取最大礼物并开方 单端队列 普通队列为单端队列,先进先出(FIFO) 只能从尾部插入,头…

jscolor 赋值input 没能引起前边色框的颜色变化

🏆本文收录于《CSDN问答解答》专栏,主要记录项目实战过程中的Bug之前因后果及提供真实有效的解决方案,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&…

操作系统内核源码杂谈篇:临界区

临界资源,是指同一时刻只能由一个线程(linux下为进程)访问的资源,而临界区就是为了确保临界资源访问是单一数据流。 临界区的代码执行,也就是进行原子操作,不会被打断。 先分析RTOS的运行架构&#xff0c…

35道最新【软件测试】面试题,常见面试题及答案汇总

前言 除了掌握扎实的专业技能之外,你还需要一份《软件测试面试宝典2024版》才能在万千面试者中杀出重围,成功拿下offer。 小编特意整理了35道测试必问必过面试题,送给大家,希望大家都能顺利通过面试,拿下高薪。赶紧码…

ngnix添加自定义模块

参考如下的 示例: hello handler 模块 部分, handler模块(100%) — Nginx开发从入门到精通 参考: 【Nginx】Nginx新增自定义模块_nginx 自定义模块-CSDN博客 需要详细说明的是, 创建一个addtion_module文件夹,将.c文件放进去&…

应急靶场(6):Linux1

目录 黑客的IP地址遗留下的三个flag 第一个flag第二个flag第三个flag 下载好靶场(应急响应靶机-Linux(1))并搭建好环境,使用帐号密码(defend / defend)登录靶机,然后使用su root命令和帐号密码(…

为hugo博客添加isso评论

个人博客评论诉求 能简单的在页面看到评论即可 能找到评论人的邮箱评论可以折叠能私有化部署 之前用过twikoo,个人体验没有isso丝滑简洁 私有化安装isso 官网 https://isso-comments.de/https://github.com/isso-comments/isso 部署方法 服务端安装python, pip 通过以下命…

“社群+”生态下的开源AI智能名片源码:驱动商业与社会连接的新引擎

摘要:在“社群”生态日益成为主流趋势的今天,开源AI智能名片源码作为技术创新与社群运营的深度融合体,正逐步展现出其重塑商业格局、深化社会连接的巨大潜力。本文旨在深入探讨开源AI智能名片源码的技术特性、在“社群”生态中的具体应用、对…

C/C++ yaml 库

文章目录 一、yaml 介绍1.1 yaml 介绍1.2 yaml 教程1.3 yaml 在线工具1.4 yaml 出现背景 二、C/C yaml 库选型2.2 libfyaml2.3 yaml-cpp 一、yaml 介绍 1.1 yaml 介绍 YAML(YAML Ain’t Markup Language)是一种人类可读的数据序列化格式,通…

在安卓手机上原生运行docker

前言 之前的文章(香橙派5plus上跑云手机方案一 redroid(带硬件加速))在Ubuntu的docker里运行安卓,这里说下怎么在安卓手机下运行docker,测试也可以跑Ubuntu。 想在手机上运行docker想的不是一天两天了,其实很久之前就有这个想法了&#xff…