【c数据结构】OJ练习篇 帮你更深层次理解链表!(相交链表、相交链表、环形链表、环形链表之寻找环形入口点、判断链表是否是回文结构、 随机链表的复制)

news2024/9/23 19:07:38

目录

一. 相交链表

二. 环形链表

三. 环形链表之寻找环形入口点

四. 判断链表是否是回文结构

五. 随机链表的复制


一. 相交链表

最简单粗暴的思路,遍历两个链表,分别寻找是否有相同的对应的结点。

  1. 我们对两个链表的每个对应的节点进行判断比较,如果不相等的话

  2. 那么我们就进行换下一对节点进行判断

但这里存在一个弊端,两条链表可能有一条长,一条短,存在节点数不一样的情况,挨个比较。

举例来说,只是举例来说:

  • 假设一个链表是6个节点,一个是8个节点,那么差值就是8

  • 那么我们让长的那个链表优先走 | 8-6 | 步,走后两个链表长度一致,就能开始进行比较了

  • 解决这个问题很简单--> 遍历计算两个链表长度求差,让长的先走完差值步,使两条链表长度一致。 

于是思路有,步骤有√

  1. 求差求两个链表长度差值
  2. 让长的链表先走差值步
  3.  遍历两个链表,分别对应是否指向相同的结点
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
 typedef struct ListNode ListNode;
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
    //1. 遍历两个链表,求他们的长度差

    //设置两个链表头结点,方便遍历
    ListNode* l1 = headA;
    ListNode* l2 = headB;
    //设置变量存放链表长度,方便求差
    int sizeA=0,sizeB=0;

    //遍历计算两条链表长度ing
    while(l1){
        sizeA++;
        l1 = l1->next;
    }
    while(l2){
        sizeB++;
        l2 = l2->next;
    }
    //求长度差
    int gap = abs(sizeA-sizeB);//abs 绝对值函数


    //2.长链表先走长度差步
    //由于不知道哪个链表长,先随便定义再判断
    ListNode* longList = headB;
    ListNode* shortList = headA;
    if(sizeA > sizeB){
        longList = headA;
        shortList = headB;
    }
    //长链表先走
    while(gap--){
        longList = longList->next;
    }
    //此时的longList和shortList在同一起跑线
    

    //3. 遍历两个链表,要么相交,要么不相交
    while(longList && shortList)//条件是两个链表都不得是空
    {
        if(longList == shortList)//找到相同结点,相交
        {
            return longList;//反正相同结点,返回long 和short 都一样
        }
        //不相同,换下一结点继续比较
        longList = longList->next;
        shortList = shortList->next;
    }
    return NULL;//循环结束,可见不相交,返回空


}

二. 环形链表

类似追击问题,若快指针在追慢指针的时候追到了,说明链表带环

 

如果链表不是带环的,那么快慢指针是绝对不会相遇的
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
typedef struct ListNode ListNode;
bool hasCycle(struct ListNode *head) {
    //创建快慢指针
    ListNode* slow = head;
    ListNode* fast = head;
    while(fast && fast->next){
        //慢指针走一步,快指针走两步,相当于快在一步一步追慢
        slow = slow ->next;
        fast = fast ->next->next;
        //相遇,说明带环
        if(fast == slow){
            return true;
        }
    }
    return false;
}

三. 环形链表之寻找环形入口点

假设meet为快慢指针相遇点

 

遍历头结点pcur和meet,因为环形,终将相遇
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
typedef struct ListNode ListNode;
struct ListNode *detectCycle(struct ListNode *head) {
    //1. 找快慢指针相遇点->说明是环形结点
    ListNode* slow = head;
    ListNode* fast = head;
    while(fast && fast ->next){
        slow = slow ->next;
        fast = fast ->next->next;
        if(fast == slow)//找到相遇点!是环形
        {
            //2. 遍历头结点和快慢指针相遇点,每次一步,其相遇点就是环形入环第一个结点
            ListNode* pcur = head; //定义头结点
            while(pcur != fast){//但凡是环形,肯定会相遇
                pcur = pcur ->next;
                fast = fast ->next;
            }
            return pcur;
        }
    }
    return NULL;
}

四. 判断链表是否是回文结构

 

先找中间结点(快慢指针)
再将中间结点之后的链表反转,最后链表左右进行比较看是否相同
/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) : val(x), next(NULL) {}
};*/
class PalindromeList {
public:
    bool chkPalindrome(ListNode* A) {
        //1. 找中间结点

        ListNode* slow = A;
        ListNode* fast = A;
        while(fast &&fast->next){
            slow = slow->next;
            fast = fast->next->next;
        }
        ListNode* mid = slow;


        //2. 根据中间结点反转后面的链表

        ListNode* n1 = NULL;//指向空
        ListNode* n2 = mid;//指向中间结点
        ListNode* n3 = n2->next;//指向n2的下一个结点
        while(n2){
            n2->next = n1;//n2指向其前一个结点(初始是空)
            n1 = n2;//n1往后走
            n2 = n3;//n2往后走
            if(n3)//前提:n3不得为空,n3才能继续往后走
            n3 = n3->next;//n3往后走
        }
        ListNode* right =n1;//n1为我反转链表的头结点


        //3. 比较原链表和反转链表的结点

        ListNode* left = A;//原链表头结点
        while(right)//反转链表的尾结点是指向空的,当其走到空,说明遍历完了
        {
            if(left->val != right->val){//有不相等的值,说明不回文
                return false;
            }
            left = left->next;
            right = right->next;
        }
        return true;
    }
};

五. 随机链表的复制

思路:

原链表上复制并插入复制结点

赋值random

断开链表

/**
 * Definition for a Node.
 * struct Node {
 *     int val;
 *     struct Node *next;
 *     struct Node *random;
 * };
 */
typedef struct Node Node;
//复制链表结点
Node* buynode(int x){
    Node* newnode = (Node*)malloc(sizeof(Node));
    newnode->val = x;
    newnode->next = newnode->random = NULL;
    return newnode;
}
//将复制的新链表插入原链表
void AddNode(Node* head){
    Node* pcur = head;//头结点
    while(pcur){
    Node* Next = pcur->next;//原链表的下一结点
    Node* newnode = buynode(pcur->val);//要复制的新结点
    
    newnode->next = Next;
    pcur->next = newnode;
    pcur = Next;//pcur走到下一结点
    }

}

struct Node* copyRandomList(struct Node* head) {
    if(head == NULL){
        return NULL;
    }
	//1. 原链表上复制结点
    //此时链表是 node1 -> newcopy1 -> node2 -> newcopy2-> node3..
    AddNode(head);
    //2. 赋值random
    Node* pcur = head;
    while(pcur){//循环修改random指针
        Node* copy = pcur->next;//此时pcur的下一结点即上一步插入的复制结点
        if(pcur->random != NULL){//因为创建新的节点时,直接让random指向空,现在只需将原链表中random不指向空的进行处理
            copy->random = pcur->random->next;
        }
        pcur = copy->next;//copy下一结点为原链表的下一结点
    }
    //3. 断开链表
    pcur = head;//让pcur回到头结点
    Node* newhead,*newtail;//为新链表创建头结点和要遍历连接的结点
    newhead = newtail = pcur->next;//pcur下一结点就是复制的新链表的头结点

    while(pcur->next->next)//因为有多插入复制的,所以pcur->next->next才是原链表下一结点
    {
        pcur = pcur->next->next;//pcur走到原链表下一结点
        newtail->next = pcur->next;//新链表连接新链表(被复制的)下一结点
        newtail = newtail->next;//新链表往后走
    }
    return newhead;//返回新链表头结点
}

 希望对你有帮助

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

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

相关文章

力扣 209.长度最小的子数组

一、长度最小的子数组 二、解题思路 采用滑动窗口的思路&#xff0c;详细见代码。 三、代码 class Solution {public int minSubArrayLen(int target, int[] nums) {int n nums.length, left 0, right 0, sum 0;int ans n 1; for (right 0; right < n; right ) { …

数通。。。

通信&#xff1a;需要介质才能通信电话离信号塔&#xff08;基站&#xff09;越远&#xff0c;信号越弱。信号在基站之间传递。你离路由器越远&#xff0c;信号越差。一个意思 比如想传一张图片&#xff0c;这张图片就是数据载荷 网关&#xff0c;分割两个网络。路由器可以是网…

Chat2VIS: Generating Data Visualizations via Natural Language

Chat2VIS:通过使用ChatGPT, Codex和GPT-3大型语言模型的自然语言生成数据可视化 梅西大学数学与计算科学学院&#xff0c;新西兰奥克兰 IEEE Access 1 Abstract 数据可视化领域一直致力于设计直接从自然语言文本生成可视化的解决方案。自然语言接口 (NLI) 的研究为这些技术的…

巴黎嫩事件对数据信息安全的影响及必要措施

2024年9月17日&#xff0c;黎巴嫩首都贝鲁特发生了多起小型无线电通信设备爆炸事件&#xff0c;导致伊朗驻黎巴嫩大使受轻伤。这一事件不仅引发了对安全的广泛关注&#xff0c;也对数据信息安全提出了新的挑战。 王工 18913263502 对数据信息安全的影响&#xff1a; 数据泄露风…

MySQL慢查询优化指南

​ 博客主页: 南来_北往 系列专栏&#xff1a;Spring Boot实战 前言 当遇到慢查询问题时&#xff0c;不仅影响服务效率&#xff0c;还可能成为系统瓶颈。作为一位软件工程师&#xff0c;掌握MySQL慢查询优化技巧至关重要。今天&#xff0c;我们就来一场“数据库加速之旅…

Thinkphp(TP)

1.远程命令执行 /index.php?sindex/think\app/invokefunction&functioncall_user_func_array&vars[0]system&vars[1][]whoami 2.远程代码执行 /index.php?sindex/think\app/invokefunction&functioncall_user_func_array&vars[0]phpinfo&vars[1][]…

Java面向对象——内部类(成员内部类、静态内部类、局部内部类、匿名内部类,完整详解附有代码+案例)

文章目录 内部类17.1概述17.2成员内部类17.2.1 获取成员内部类对象17.2.2 成员内部类内存图 17.3静态内部类17.4局部内部类17.5匿名内部类17.5.1概述 内部类 17.1概述 写在一个类里面的类叫内部类,即 在一个类的里面再定义一个类。 如&#xff0c;A类的里面的定义B类&#x…

微信支付商户号注册流程

目录 一、官方指引二、申请规则三、申请流程1.提交资料2.签约协议3.绑定场景 四、微信支付商户登录入口 一、官方指引 https://kf.qq.com/faq/210423UrIRB7210423by6fQn.html 二、申请规则 1、微信支付商家仅面向企业、个体工商户、政府及事业单位、民办非企业、社会团体、基…

java sdk下载,解决下载了java但是编译不了

直接搜Java得到的网站使用不了的 应该只是个功能包或者版本太低用不了 得去oracle公司搜java这个产品去下载

Java语言程序设计基础篇_编程练习题**18.34 (游戏:八皇后问题)

目录 题目&#xff1a;**18.34 (游戏:八皇后问题) 代码示例 代码解析 输出结果 使用文件 题目&#xff1a;**18.34 (游戏:八皇后问题) 八皇后问题是要找到一个解决方案&#xff0c;将一个皇后棋子放到棋盘上的每行中&#xff0c;并且两个皇后棋子之间不能相互攻击。编写个…

Llama 3.1 技术研究报告-2

3.3 基础设施、扩展性和效率 我们描述了⽀持Llama 3 405B⼤规模预训练的硬件和基础设施&#xff0c;并讨论了⼏项优化措施&#xff0c;这些措施提⾼了训练效率。 3.3.1 训练基础设施 Llama 1和2模型在Meta的AI研究超级集群&#xff08;Lee和Sengupta&#xff0c;2022&#x…

模型融合创新性Max!5种模型融合方法刷新SOTA!发顶会必看!

近年来&#xff0c;关于模型融合的研究逐渐火热&#xff0c;出现了很多效果出众的成果。模型融合&#xff08;Model Merging&#xff09;技术&#xff0c;即利用现有模型的参数、架构和特性&#xff0c;巧妙结合成一个新的、功能更强大的模型&#xff0c;这不仅减少了从头训练大…

计算机毕业设计新闻资讯知识施肥技术网站推荐评论搜索猜你喜欢留言/springboot/javaWEB/J2EE/MYSQL数据库/vue前后分离小程序

摘要‌ 随着互联网的快速发展&#xff0c;新闻网站成为人们获取新闻资讯的重要途径。本文旨在介绍一款新闻网站毕业设计的开发与实现过程&#xff0c;该系统集新闻发布、用户互动、个性化推荐等功能于一体&#xff0c;采用Spring Boot、Vue等前后端分离技术&#xff0c;旨在提…

风力发电场集中监控解决方案

0引言 风力发电装机容量近年来快速增长。截至7月底&#xff0c;全国发电装机容量达27.4亿千瓦&#xff0c;同比增长11.5%。其中&#xff0c;太阳能和风力发电装机容量分别为4.9亿千瓦和3.9亿千瓦&#xff0c;同比增长42.9%和14.3%。风力发电场分陆上和海上风电&#xff0c;常位…

asp.net core grpc快速入门

环境 .net 8 vs2022 创建 gRPC 服务器 一定要勾选Https 安装Nuget包 <PackageReference Include"Google.Protobuf" Version"3.28.2" /> <PackageReference Include"Grpc.AspNetCore" Version"2.66.0" /> <PackageR…

C++ 异步编程中:future与promise、packaged_task、async

原文链接&#xff1a;C 异步编程之future与promise、async、packaged_task_std::promise和std::future异步发送-CSDN博客 1、std::future std::future类模板来关联线程运行的函数和函数的返回结果&#xff0c;这种获取结果的方式是异步的 std::future 通常由某个 Provider 创建…

BOE(京东方)携故宫博物院举办2024“照亮成长路”公益项目落地仪式以创新科技赋能教育可持续发展

2024年9月20日&#xff0c;BOE&#xff08;京东方&#xff09;“照亮成长路”智慧教室落成暨百堂故宫传统文化公益课山西活动落地仪式在山西省太原市娄烦县实验小学隆重举行。自“照亮成长路”教育公益项目正式设立以来&#xff0c;BOE&#xff08;京东方&#xff09;持续以创新…

食家巷苦豆粉,香得很哟

苦豆粉&#xff0c;它看似普通&#xff0c;却承载着西北的厚重历史与浓郁风情。那一抹淡淡的绿色粉末&#xff0c;蕴含着大自然的馈赠和西北人民的智慧。 苦豆&#xff0c;这种生长在西北土地上的植物&#xff0c;经过精心研磨&#xff0c;变成了细腻的苦豆粉。它的味道独特&am…

Kimi助你快速完成开题报告【超详细实操教程】

随着人工智能的飞速发展&#xff0c;AI技术已经渗透到我们生活的方方面面&#xff0c;包括学术研究。在接下来的文章中手把手教你如何利用AI工具来优化每一个部分&#xff0c;让你的开题报告不仅内容丰富&#xff0c;而且结构严谨&#xff0c;逻辑清晰&#xff0c;为你的毕业论…

01.前端面试题之ts:说说如何在Vue项目中应用TypeScript?

文章目录 一、前言二、使用Componentcomputed、data、methodspropswatchemit 三 、总结 一、前言 与link类似 在VUE项目中应用typescript&#xff0c;我们需要引入一个库vue-property-decorator&#xff0c; 其是基于vue-class-component库而来&#xff0c;这个库vue官方推出…