数据结构:单链表OJ题

news2024/11/26 14:33:49

目录

  • 相交链表
    • 解题思路
    • 代码
  • 环形链表(I)
    • 解题思路
    • 代码
  • 环形链表(II)
    • 解题思路
    • 代码
  • 随机链表的复制(深拷贝)
    • 解题思路
    • 代码

相交链表

题目描述:
在这里插入图片描述
案例:
在这里插入图片描述
在这里插入图片描述
题目链接:https://leetcode.cn/problems/intersection-of-two-linked-lists/description/

解题思路

既然要验证链表是不是相交的链表,就必须创建两个指针分别指向两个链表,当遍历时只要由一个节点满足两个指针相等,就说明是相交链表。
这里就要分情况了:

  1. 当两个链表长度相同时,让两个指针依次遍历数据直到两个指针相等或者有一个遍历结束置为NULL,相等就相交,反之则不相交。
  2. 两个链表长度不同,我们想让他们通过常规遍历肯定是不行了,但是根据第一种情况,我们可以通过一些操作使得两个链表长度相等,也就是两个指针在同一起跑线上,这样就把第二种情况转化成了第一种情况。
    那么怎么让两个指针在同一起跑线上,很简单,遍历两个指针,计数他们的长度,求出长度相差的绝对值n,让长节点的指针先走n步,然后两个链表再同时遍历即可。

代码

/**结构体格式
 * 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) {
    ListNode* l1=headA;
    ListNode* l2=headB;
    int num1,num2,tmp;//定义链表大小以及绝对值
    num1 =num2 =0;
    //求链表长度
    while(l1)
    {
        num1++;
        l1=l1->next;
    }
    while(l2)
    {
        num2++;
        l2=l2->next;
    }
     //定义长短链表
    ListNode* l=NULL;//长链表
    ListNode* s=NULL;//短链表
    if(num1>num2)
    {
        tmp=num1-num2;
        l=headA;
        s=headB;
    }
    else
    {
        tmp=num2-num1;
        l=headB;
        s=headA;
    }
    //长链表先走n步
    while(tmp--)
    {
        l=l->next;
    }
    //两个链表同时遍历
    while(l&&s)
    {
        if(l==s)
        {
            return l;
        }
        l=l->next;
        s=s->next;
    }
    return NULL;
}

环形链表(I)

题目描述:
在这里插入图片描述
案例:
在这里插入图片描述
题目链接:https://leetcode.cn/problems/linked-list-cycle/description/

解题思路

这个题目很简单,是比较经典的快慢指针问题。
快慢指针:定义两个指针,一个走得慢,一个走得快。
解题:
定义两个指针,一个快指针一个慢指针,慢指针一次走一步,快指针一次走两步,因为是环形链表,所以不会走到NULL,当碰到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)//快慢指针遍历
    {
    	//这里注意让指针先走在判断,刚开始两个指针都是指向首地址,如果不走直接判断就会导致无论什么情况都是有环的。
        fast=fast->next->next;
        slow=slow->next;
        if(fast==slow)
        {
            return true;
        }
    }
    return false;
}

环形链表(II)

题目描述:
在这里插入图片描述
案例:
在这里插入图片描述
题目链接:https://leetcode.cn/problems/linked-list-cycle-ii/description/

解题思路

先通过快慢指针找到公共节点meet。
让⼀个指针从链表起始位置开始遍历链表,同时让⼀个指针从判环时相遇点(meet)的位置开始绕环运行,两个指针都是每次均⾛⼀步,最终肯定会在入口点的位置相遇。
可能会有人觉得不一定,这个只会在一些特定情况下实现,我们可以来试着证明一下。
在这里插入图片描述
注:M为相遇点,E为入环点,环长度为R
要满足上面的结论,就要满足L=R-X
我们可以通过快慢指针之间的关系来证明这个关系式的可靠性(慢指针走一步,快指针走2步)。
慢指针走的路程:L+X
快指针走的路:L+X+nR
既然他们能够相遇,就可以满足2*(L+X)=L+X+nR(快指针走的是慢指针的两倍)
进一步推导:
L+X=nR
L=nR-X
因为这是一个环,所以无论n是多少,他走完一圈就会再次回到原点,所以n在这里对这个关系式就没有影响,由此可得,上述结论是可行的。

代码

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
 typedef struct ListNode ListNode;
struct ListNode *detectCycle(struct ListNode *head) {
    ListNode* slow,*fast;
    slow=fast=head;
    while(fast&&fast->next)
    {
        fast=fast->next->next;
        slow=slow->next;
        if(fast==slow)//寻找相遇点
        {
            ListNode* meet=fast;//定义相遇点,为了可观性进行了重定义,也可以直接使用fast/slow
            ListNode* pcur=head;
            while(pcur!=meet)//两个指针开始遍历
            {
                pcur=pcur->next;
                meet=meet->next; 
            }
            return meet;
        }
    }
    return NULL;
}

随机链表的复制(深拷贝)

题目描述:
在这里插入图片描述
案例:
在这里插入图片描述
题目链接:https://leetcode.cn/problems/copy-list-with-random-pointer/description/

解题思路

  1. 创建新的链表,并且与原链表产生联系,将新链表的random初始化为NULL
    在这里插入图片描述

  2. 修改新链表的random
    分析题目可得,我们复制的链表中随机指针也要对应原链表在新链表中对应的位置。
    定义新链表为copy,观察上图,我们要修改新链表的random,只需要将新链表的random指向原链表指向的random->next。当原链表中random指向NULL,就不需要再做处理,因为我们初始化就是置random为NULL。
    举个例子:以13节点为例
    我们新链表中13节点要指向新链表7节点,7节点的位置再原链表13节点random指向的节点的下一个节点。
    pcur为我们创建的原链表头节点
    即copy->random=pcur->random->next;

    经过分析就可得,我们要创建两个指针分别指向新旧链表得头节点。

  3. 断开新旧链表的联系
    我们将原链表头节点走到要修改的新链表后面一个节点的位置,如图:
    在这里插入图片描述
    newhead为新链表头节点地址,newtail为新链表尾节点地址,
    将newtail->next指向pcur->next,
    将newtail向后移一位,pcur一直赋值为newtail的后一位。

代码

/**
 * 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;
}
struct Node* copyRandomList(struct Node* head) {
    if(head==NULL)//当链表为NULL单独处理
    {
        return NULL;
    }
	Node* pcur=head;
    //将新链表与原链表创建联系
    while(pcur)
    {
        Node* newnode=BuyNode(pcur->val);
        newnode->next=pcur->next;
        pcur->next=newnode;
        pcur=newnode->next;
    }
    //修改新链表的random
    pcur=head;
    while(pcur)
    {
        Node* copy=pcur->next;
        if(pcur->random!=NULL)
        {
            copy->random=pcur->random->next;
        }
        pcur=copy->next;
    }
    //将新链表与原链表断开联系
    pcur=head;
    Node* newHead,*newTail;
    newHead=newTail=pcur->next;
    while(pcur->next->next)
    {
        pcur=newTail->next;
        newTail->next=pcur->next;
        newTail=newTail->next;
    }
    return newHead;
}

----------------------------------------------------------------分隔符
西靠:慢指针走一步,快指针走3步、4步、5步…,快慢指针是否会相遇?
答案:一定会相遇。因为篇幅太长,就不做过多解释了。
有兴趣的可以尝试一下,当然也可以记住结论以后使用知道即可。
感谢各位的观看,有错请在评论区指正,谢谢!

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

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

相关文章

从边缘云到边缘AI,似乎边缘更有想象空间,你认同么?

【科技明说 | 科技热点关注】 前些天,我看到一个业内的行业分析说,边缘人工智能已经开始兴起,但是要到了2026年才会产生影响。这就意味着边缘AI的未来值得关注一下。 什么是边缘AI?边缘AI就是将人工智能处理功能带到了…

怎么找矩阵系统,怎么源码搭建,源头技术开发需要哪些支持

一、引言 在进行矩阵系统源码搭建时,选择合适的工具至关重要。正确的工具选择不仅可以提高开发效率,还能确保系统的稳定性、可扩展性和性能。本文将探讨在矩阵系统源码搭建过程中如何选择合适的工具。 二、前端开发工具选择 前端框架 React:由…

LLM大模型怎样进行数据和质量测试

大型语言模型(LLMs)的四种测试策略 测试机团队需要一套针对LLM的测试策略。在为嵌入在AI agent应用中的LLMs大模型制定测试策略时,可以考虑以下四点实践方法: 1)创建测试数据以扩展软件质量保证 2&#xff09…

C 盘又满了?试试我用的这个方法吧,轻松腾出几十个G,还有好用的工具推荐哟!

如题,作为具有洁癖的程序猿,作为具有容量焦虑症的程序猿,我总是希望C盘保持轻巧状态(看来还是Mac比较省心),奈何我给了它200G的存储,安装的应用都保存到了D盘,可它还是蹭蹭飙升&…

第一个Flutter应用解析(一)

1、创建项目 1.1 新建 1.2 选择Flutter SDK的位置 1.3 项目名称 英文单词加下划线起名规范,其他默认即可。 1.4 点击运行 发生报错显示我们的JAVA版本不符合 1.5 更改版本设置 1.6 再次启动项目 2、分析页面代码 以下是lib/main.dart的源代码(为了阅…

搭建企业私有云

A公司为国内知名大型瓶装饮料合资企业。2019年以前业务系统部署于IBM 的Unix小型机,该机型在IBM结束支持后,一直购买专业公司运维服务。Unix系统软件和运维成本相较Linux X86平台要高很多,不能满足应用轻量化和快速叠代的需求。公司原有的基础…

儿童护眼灯哪个牌子好?儿童护眼灯推荐测评教你选护眼台灯!

​据调查,我国现有盲人500多万,低视力近千万人,尤其是在儿童及青少年当中,患病率极高。全国学生体质健康调研最新数据表明,我国儿童青少年总体近视率为52.7%,其中,小学生为42%,初中生为80.7%&am…

机器学习【医疗领域及其药品搭建】

机器学习【医疗领域及其药品搭建】 1. 个性化医疗与精准治疗2. 药物管理2. 药物研发与创新4. 医疗图像分析与诊断辅助5. 数据安全与隐私保护6. 药物安全与风险管理7. 电子健康记录(EHR)的利用8. 机器人辅助手术 1. 个性化医疗与精准治疗 基因组学&#…

Leetcode 完全平方数

这段代码是用 动态规划(Dynamic Programming, DP)来解决 LeetCode 第279题「完全平方数」的问题,题目要求给定一个整数 n,找出若干个完全平方数(如1, 4, 9, 16等)的和,恰好等于 n,并…

【韩顺平Java笔记】第8章:面向对象编程(中级部分)【314-326】

314. 动态绑定机制 【注】属性没有动态绑定机制 虽然B类sum被注释掉了,但是其父类A类的sum方法没被注释掉,所以调用的是A类的sum方法,A类的sum方法中有个getI()方法,根据动态绑定机制,现在这个a引用的运行类型是B类&a…

【CTF Web】Pikachu getimagesize() Writeup(文件上传+PHP+文件包含漏洞+JPEG图片马+getimagesize绕过)

不安全的文件上传漏洞概述 文件上传功能在web应用系统很常见,比如很多网站注册的时候需要上传头像、上传附件等等。当用户点击上传按钮后,后台会对上传的文件进行判断 比如是否是指定的类型、后缀名、大小等等,然后将其按照设计的格式进行重…

mongodb 数据迁移,亲测成功!

mysql进行数据迁移,最简单的不过是导出sql,然后在运行sql,数据也自然迁移过去了。 可是mongodb里,我们存储的是文件,是怎么做到的呢,当我在翻阅网上博客的时候,并没有发现有这方面的顾虑。 当…

制造业DT数字化之生产制造业务建模

一、工厂建模为何物? 对制造业人员(人)、设备(机)、材料(料)、工艺流程(法)、工厂环境(环)数据化管理的过程就叫工厂建模。 二、制造建模有哪几大…

Math.js 进阶使用:数值比较和数学运算

一. 引言 上篇文章中,我们了解了 Math 工具函数在数值操作方面的妙用,主要包括:取绝对值、向上向下取整以及四舍五入的方法,详细了解请参考上一篇文章: Math 工具函数的妙用:常用的数值操作 本篇文章将继…

【Linux系统编程】第三十弹---软硬链接与动静态库的深入探索

✨个人主页: 熬夜学编程的小林 💗系列专栏: 【C语言详解】 【数据结构详解】【C详解】【Linux系统编程】 目录 1、软硬链接 1.1、见一见 1.2、特征 1.3、什么是软硬链接?有什么用(为什么)? 2、动态库和静态库 2.…

从 Vim 到 VSCode:提升远程开发效率的秘密武器

1.前言 在 Linux 服务器上进行开发时,我们常常会选择使用 vi 或 vim 这些轻量级的编辑器。虽然它们可以满足基本的编辑需求,但在处理大型项目时,局限性很明显:缺乏现代编辑器的高级功能,比如语法高亮、代码补全以及便…

windows 调整虚拟内存文件大小,释放C盘

Windows 虚拟内存文件(通常是 pagefile.sys)的作用是充当物理内存(RAM)的扩展,当系统内存不足时,它为系统提供一个额外的、基于硬盘的存储空间。这种虚拟内存的机制帮助系统在物理内存耗尽时仍能继续运行程…

数据结构 ——— 单链表oj题:相交链表(链表的共节点)

目录 题目要求 手搓两个相交简易链表 代码实现 题目要求 两个单链表的头节点 headA 和 headB ,请找出并返回两个单链表相交的起始节点,如果两个链表不存在相交节点,则返回 NULL 手搓两个相交简易链表 代码演示: struct Lis…

SpringSecurity(一)——认证实现

一、初步理解 SpringSecurity的原理其实就是一个过滤器链,内部包含了提供各种功能的过滤器。 当前系统中SpringSecurity过滤器链中有哪些过滤器及它们的顺序。 核心过滤器: (认证)UsernamePasswordAuthenticationFilter:负责处理…

LabVIEW提高开发效率技巧----状态保存与恢复

在LabVIEW开发中,保存和恢复程序运行时的状态是一个关键技巧,特别是在涉及需要暂停或恢复操作的应用中。通过使用 Flatten To String 和 Unflatten From String 函数,开发人员可以将程序当前的状态转换为字符串并保存,再在需要时恢…