【数据结构练习】单链表OJ题(二)

news2024/11/19 20:39:28

目录

    • 一、相交链表
    • 二、环形链表1
    • 三、环形链表2
    • 四、链表分割
    • 五、复制带随机指针的链表

一、相交链表

题目:
在这里插入图片描述
示例:
在这里插入图片描述
注意:不能根据节点的值来比较是否相交,而是根据节点在内存中是否指向相同的位置。

例如以上图:

链表A:4、1、8、4、5
链表B:5、6、1、8、4、5

链表A和链表B都有节点的值为1,但是它们在内存中指向不同的位置,而值为8的节点(A的第三个节点、B的第四个节点)则在内存中指向相同的位置。

大体思路:链表A和链表B如果相交,那么它们的后几个或者一个节点的位置是一样的。它们的长度不一定一样长,所以要先计算出链表A和链表B的长度,让较长的链表先走长度差的距离,然后再同时走,直到两个链表相交,返回那个开始相交的节点。

计算链表长度:
分别定义一个变量遍历链表,不为空计数器加1往后走,直到循环结束跳出。

如果没有相交返回空:
此时分别遍历两个链表的指针已经走到尾了。假设两个链表有相交,不管是一个还是多个,那么这两个指针肯定是一样的(指相交);如果两个链表不相交,即使是最后的节点也同样不相交,所以就直接返回NULL。

较长的链表先走节点数之差:
用一个变量等于链表长度之差,因为并不知道是A链表长还是B链表长,所以使用绝对值函数abs。先假设是A链表长,B链表短。设置一个条件,如果A链表的长度小于B链表的长度,就反过来。如果假设的是对的,较长的链表先走长度之差的距离。

一起走,直到相交:
两个链表同时走到某个节点相交了,就跳出循环,然后赋给新的头指针,并且返回这个头指针。

struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
    int len1=0;
    int len2=0;
    struct ListNode *cur1=headA;
    struct ListNode *cur2=headB;
    //先算出两个链表的节点数
    while(cur1)
    {
        len1++;
        cur1=cur1->next;
    }
    while(cur2)
    {
        len2++;
        cur2=cur2->next;
    }
    //如果没有相加点返回空
    if(cur1!=cur2)
    {
        return NULL;
    }
    //长的先走节点数之差
    int k=abs(len1-len2);
    struct ListNode *longhead=headA;
    struct ListNode *shorthead=headB;
    if(len1<len2)
    {
        longhead=headB;
        shorthead=headA;
    }
    while(k)
    {
        longhead=longhead->next;
        k--;
    }
    //一起走,直到相交
    while(longhead!=shorthead)
    {
        longhead=longhead->next;
        shorthead=shorthead->next;
    }
    struct ListNode *newhead=longhead;
    return newhead;
}

二、环形链表1

题目:
在这里插入图片描述
使用的是双指针法

定义两个快慢指针fast和slow,从起点出发。先fast一次走两步,slow一次走一步,再判断两个指针是否相同。如果链表有环,那么fast或者fast->next永远不为空,一直在循环里转;如果链表没有环,fast又走得比slow快,所以fast或者fast->next到空就结束。这里fast比slow快一步,即每次距离缩短1步,所以只要有环,fast先在环里转,然后slow随后进环,每次它们的距离缩短1,最终相遇。

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

三、环形链表2

题目:
在这里插入图片描述
这题与上面的题多增加了一个设定,如果有环,返回的是开始入环的第一个节点。没有环返回空。

那么始入环的第一个节点怎么找呢?其实这里是有关数学计算的。

还是使用两个快慢指针,fast一次走两步,slow一次走一步。如果链表没有环,fast或者fast->next为空,然后返回空指针。如果链表有环,在环的某个位置相遇(注意:fast先入环,可能已经在环里转了n圈了)。假设相遇点与入环点的距离为x,起始点到入环点的距离为L,环的剩下的距离为nC-x(n表示fast已经在环里转了n圈)。

fast从起始点到相遇点的距离为:L+nC+x
slow从起始点到相遇点的距离为:L+x

因为fast一次的步长为slow的两倍

所以:
2(L+x)=L+nC+x
L+x=nC
L=nC-x

根据数学计算转换为:两个指针分别一个从相遇点走,另一个从起始点走,以相同的步长,它们会在入环的第一个节点相遇,然后返回这个相遇点就是入环的第一个节点。

在这里插入图片描述

struct ListNode *detectCycle(struct ListNode *head) {
    struct ListNode *slow=head;
    struct ListNode *fast=head;
    while(fast&&fast->next)
    {
        fast=fast->next->next;
        slow=slow->next;
        if(slow==fast)
        {
            struct ListNode *rid=slow;
            struct ListNode *mrid=head;
            while(rid!=mrid)
            {
                rid=rid->next;
                mrid=mrid->next;
            }
            return rid;
        }
    }
    return NULL;
}

四、链表分割

题目:
在这里插入图片描述
假设一个链表为:

2、3、1、4、2、5

假设x等于3,数据小于的3的节点有:2、1、2
大于等于3的节点有:3、4、5

题目要求将小于x的节点排在其余节点之前,并且不能改变原来的数据顺序。

大体思路:这里我们可以采用分为两个链表的方式。将数据小于x的节点放在一个A链表里,大于等于的放在B链表里。然后把A链表的尾节点与B链表的头节点连接起来。

但是这里要注意一个问题,如果A链表没有节点怎么与B链表连接,这种情况要单独判断,比较麻烦。所以我们可以采用创建哨兵位头节点解决这个问题。

注意:最后B链表的尾节点要指向空指针,同时释放两个哨兵位节点,返回第一个有效节点。
在这里插入图片描述

class Partition {
public:
    ListNode* partition(ListNode* pHead, int x) {
        struct ListNode* cur=pHead;
        struct ListNode* head1, *tail1, *head2, *tail2;
        head1=tail1=(struct ListNode*)malloc(sizeof(struct ListNode));
        head2=tail2=(struct ListNode*)malloc(sizeof(struct ListNode));
        while(cur)
        {
            if(cur->val<x)
            {
                tail1->next=cur;
                tail1=tail1->next;
            }
            else
            {
                tail2->next=cur;
                tail2=tail2->next;
            }
            cur=cur->next;
        }
        tail2->next=NULL;
        tail1->next=head2->next;
        struct ListNode* newhead=head1->next;
        free(head1);
        free(head2);
        return newhead;
    }
};

五、复制带随机指针的链表

题目:
在这里插入图片描述
要拷贝原节点,并且拷贝节点的随机指针也要指向对应的节点,最后还原原链表。

每个拷贝节点都在原节点的后面:
用一个变量cur遍历链表,只要不为空每次进入循环先定义一个变量next记录原链表的下一个位置(cur在原链表的下一个位置,方便一次拷贝完找到),然后开辟一块空间copy为拷贝节点,把原节点的值赋给拷贝节点,再让cur的下一个地址为copy,copy连接next。
在这里插入图片描述
置每个拷贝random:
原链表的每个节点的random指针都有对应的指向,拷贝节点也要有random指针对应的指向,只是拷贝节点的random指针要与原节点的random指针指向保持一致。比如原节点13的random指针指向原节点的7,那么拷贝节点13的random指针则指向拷贝节点的7。

问题是拷贝节点的random指针怎么找到它对应的节点呢?其实上面一步把每个拷贝节点放在原节点的后面有一个好处,方便这一步找到它的random指针。

以拷贝节点13为例:拷贝节点13的random指针,就是它的原节点的random指针所指向的原节点的下一个节点。如果原节点的random指向空,拷贝节点的randon也是指向空。

在这里插入图片描述
拷贝节点解下来,尾插在一起,恢复原链表:
在这里插入图片描述

struct Node* copyRandomList(struct Node* head) {
	struct Node* cur=head;
    //复制某个节点到原节点的后面
    while(cur)
    {
        struct Node* next=cur->next;
        struct Node* copy=(struct Node*)malloc(sizeof(struct Node));
        copy->val=cur->val;
        cur->next=copy;
        copy->next=next;
        cur=next;
    }
    cur=head;
    //处理拷贝节点的random指针指向
    while(cur)
    {
        struct Node* copy=cur->next;
        if(cur->random==NULL)
        {
            copy->random=NULL;
        }
        else
        {
            copy->random=cur->random->next;
        }
        cur=copy->next;
    }
    cur=head;
    //把拷贝指针连接起来,还原原来的链表
    struct Node* newhead=NULL;
    struct Node* tail=NULL;
    while(cur)
    {
        struct Node* copy=cur->next;
        struct Node* next=copy->next;
        if(tail==NULL)
        {
            newhead=tail=copy;
        }
        else
        {
            tail->next=copy;
            tail=tail->next;
        }
        cur->next=next;
        cur=next;
    }
    return newhead;
}

在这里插入图片描述
感谢观看~

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

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

相关文章

ATFX汇市:美元指数疯狂上涨,英镑单日贬值近1%

环球汇市行情摘要—— 昨日&#xff0c;美元指数上涨0.55%&#xff0c;收盘在103.95点&#xff0c; 欧元贬值0.50%&#xff0c;收盘价1.0810点&#xff1b; 日元贬值0.69%&#xff0c;收盘价145.84点&#xff1b; 英镑贬值0.98%&#xff0c;收盘价1.2600点&#xff1b; 瑞…

火山引擎边缘云,助你沉浸式回忆童年

发现了吗&#xff1f;在抖音、西瓜视频上能观看4K修复的经典港片了&#xff01;得益于抖音、中国电影资料馆、火山引擎共同发起的“经典香港电影修复计划”&#xff0c;我们童年时期看过的《大话西游之大圣娶亲》《武状元苏乞儿》等22部港片以更清晰、流畅、颜色饱满的状态回归…

基于Java+SpringBoot+vue前后端分离可盈保险合同管理系统设计实现

博主介绍&#xff1a;✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专…

【数据库】使用ShardingSphere+Mybatis-Plus实现读写分离

书接上回&#xff1a;数据库调优方案中数据库主从复制&#xff0c;如何实现读写分离 ShardingSphere 实现读写分离的方式是通过配置数据源的方式&#xff0c;使得应用程序可以在执行读操作和写操作时分别访问不同的数据库实例。这样可以将读取操作分发到多个从库&#xff08;从…

十二、pikachu之URL重定向

文章目录 1、URL重定向概述2、实战3、URL跳转的几种方式:3.1 META标签内跳转3.2 javascript跳转3.3 header头跳转 1、URL重定向概述 不安全的url跳转问题可能发生在一切执行了url地址跳转的地方。如果后端采用了前端传进来的&#xff08;可能是用户传参&#xff0c;或者之前预埋…

Allegro平台如何利用测评打造爆款产品,优化listing提升曝光度!

Allegro是波兰本土最大的电商平台&#xff0c;1999年由波兰人自己创造成立&#xff0c;75%的波兰人都知道该网站&#xff0c;Allegro的品牌认知度在波兰高达98%。也是东欧“最大”拍卖网站。 波兰的消费者非常熟悉Allegro平台&#xff0c;大部分波兰人如果想要购买商品&#x…

[uniapp] scroll-view 简单实现 u-tabbar效果

文章目录 方案踩坑1.scroll-view 横向失败2.点击item不滚动?3. scrollLeft从哪里来? 效果图 方案 官方scroll-view 进行封装 配合属性 scroll-left Number/String 设置横向滚动条位置 即可 scroll-into-view 属性尝试过,方案较难实现 踩坑 1.scroll-view 横向失败 安装…

很奇葩的Deepin下Miniconda安装之旅

前文写到安装富瀚微的工具链遇到的问题&#xff0c;接着又遇到了Miniconda的问题&#xff0c;始终停留在END这个页面。 弄了很久&#xff0c;最终怀疑是不是前面什么安装包搞错了&#xff0c;系统重装一遍&#xff0c;还是一样的问题。一通乱操作后&#xff0c;得以解决。现将过…

【AI】即使AI 时代,程序员也无需焦虑

&#x1f680;欢迎来到本文&#x1f680; &#x1f349;个人简介&#xff1a;陈童学哦&#xff0c;目前学习C/C、算法、Python、Java等方向&#xff0c;一个正在慢慢前行的普通人。 &#x1f3c0;系列专栏&#xff1a;陈童学的日记 &#x1f4a1;其他专栏&#xff1a;CSTL&…

ARP攻击分析案例

1.用户需求 最近&#xff0c;医院的部分科室工作人员反映网络时不时会出现卡顿现象。尽管网络管理员已经采用了相关技术进行排查&#xff0c;但并未发现异常情况。因此&#xff0c;我们建议借助NetInside系统进一步分析和定位问题。 2.详细分析 针对上述异常问题&#xff0c…

第五十七章 恶魔通缉令

“嗐&#xff01;居然查来查去没查着&#xff01;” 坎迪摇摇头&#xff0c;继续道&#xff0c;“突然&#xff01;你猜怎么着&#xff1f;我居然感觉天空有双眼睛在盯着我&#xff0c;吓得我都不敢抬头看&#xff01;只觉得周身痒痒&#xff0c;却有一股力量迫使我缩颈闭嘴&am…

某网站DES加密逆向分析实战

文章目录 一、抓包分析二、加密分析一、重写加密 一、抓包分析 分析站点&#xff1a; aHR0cDovL2VpcC5jaGFuZmluZS5jb20v 首先我们提交一下登陆信息&#xff1a; 搜索j_password查看加密函数: 把上图搜索到的encryptPassword函数拿出来分析一下&#xff1a; function encryptP…

微客云直充卡券优惠话费充值接口开发稳定高效

微客云直充卡券话费 开发团队致力于此模块生命力至少3-5年 此模块以资源种类&#xff0c;官方直联接口为优势&#xff0c;不纯以软件更新为主&#xff0c;力争版本精准化服务用户 单独直充卡券话费系统&#xff0c;直接完成对各种消费场景的流量变现&#xff0c;更加开放与链路…

【RuoYi移动端】uniApp导入和引用uView2.0插件

一、打开uiew官网 安装 | uView 2.0 - 全面兼容 nvue 的 uni-app 生态框架 - uni-app UI 框架uView UI&#xff0c;是 uni-app 生态最优秀的 UI 框架&#xff0c;全面的组件和便捷的工具会让您信手拈来&#xff0c;如鱼得水https://uviewui.com/components/install.html 也可直…

香港服务器怎么打开SSH

​  SSH是一种远程登录协议&#xff0c;可以通过加密方式在网络上安全地传输数据。它允许用户在远程服务器上执行命令&#xff0c;管理文件和目录&#xff0c;并进行其他系统管理任务。 如何打开SSH服务? 1.确认已安装OpenSSH服务器&#xff1a; 你可以通过命令sudoapt-geti…

爬虫逆向实战(二十二)--某恩数据电影票房

一、数据接口分析 主页地址&#xff1a;某恩数据 1、抓包 通过抓包可以发现数据接口是API/GetData.ashx 2、判断是否有加密参数 请求参数是否加密&#xff1f; 无请求头是否加密&#xff1f; 无响应是否加密&#xff1f; 通过查看“响应”模块可以发现&#xff0c;响应是…

apache的ab工具测试网页优化效果速度以及服务器承载

今天为大家介绍一款apache自带的一种的测试网页优化效果速度以及服务器承载的工具——ab.exe。 大家在工作中或者开发中可以使用apache的ab工具来测试自己的网站并发量大小&#xff0c;和某个页面的访问时间。 一、基本用法 如果你是用的是apache的话&#xff0c;那么只要进…

opencv案例03 -基于OpenCV实现二维码生成,发现,定位,识别

1.二维码的生成 废话不多说&#xff0c;直接上代码 # 生成二维码 import qrcode# 二维码包含的示例数据 data "B0018" # 生成的二维码图片名称 filename "qrcode.png" # 生成二维码 img qrcode.make(data) # 保存成图片输出 img.save(filename)img.sh…

Windows操作系统打开Sketch文件的实用技巧!

在设计工作中&#xff0c;Sketch是一款非常受欢迎的矢量绘图软件&#xff0c;但由于它只能兼容Mac操作系统&#xff0c;对设计师有一定的局限性&#xff0c;Sketch的使用问题就成了困扰。今天本文将为大家分享一个在Windows系统也能打开Sketch文件的操作方法&#xff0c;一起来…