单链表经典oj题(2)

前言

这次将要把剩下的oj题将以图解和自己的理解把它讲解完,希望对大家有所帮助,这次的讲解也是干货

第一题

21. 合并两个有序链表 - 力扣(LeetCode)

ok这次就简单点,大家自己去看题目了

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

暴力思路

想想看不考虑空间和时间的消耗,什么代码最容易想

两个链表,可不可以直接把两个链表的值放在一个数组中

然后再排序,当然这里的链表大小是有序的,放在数组中时

可以判断大小,从而不用去排序

再根据数组自行去malloc一个链表,是不是非常暴力的思路

这个暴力代码其实也很重要,至少是算法小白入门的绝招

#include<stdio.h>
#include<stdlib.h>
typedef struct SlistNode {
   struct SlistNode* next;
   int val;
}SLNode,*SL;
SLNode* Buyslistnode(int data)
{
	SL newnode = (SL)malloc(sizeof(SLNode));
	newnode->next = NULL;
	newnode->val = data;
	return newnode;
}
SL initlist1()
{
	SL list1 = (SL)malloc(sizeof(SLNode));
	list1->val = 1;
	list1->next = Buyslistnode(2);
	list1->next->next = Buyslistnode(4);
	return list1;
}
SL initlist2()
{
	SL list2 = (SL)malloc(sizeof(SLNode));
	list2->val = 1;
	list2->next = Buyslistnode(3);
	list2->next->next = Buyslistnode(4);
	return list2;
}
int cmp(const void* p1, const void* p2)
{
	return *(int*)p1 - *(int*)p2;
}
void text1()
{
	//我们这里直接考虑list1与list2都不是空链表的情况
	//其实其他的情况可以通过if判断排除
	//初始化题目
	//list1   1->2->4
	//list2   1->3->4
	SL list1 = initlist1();
	SL list2 = initlist2();
	//题目中链表的结点数是0~50
	//所以直接可以用静态数组
	int newarr[110];
	int size = 0;
	while (list1)
	{
		newarr[size++] = list1->val;
		list1 = list1->next;
	}
	while (list2)
	{
		newarr[size++] = list2->val;
		list2 = list2->next;
	}
	qsort(newarr, size, sizeof(int), cmp);
	SL phead = (SL)malloc(sizeof(SLNode));
	SL cur = phead;
	for (int i = 0; i < size; i++)
	{
		cur->next = Buyslistnode(newarr[i]);
		cur = cur->next;
	}
	//至此已经完成
	//打印看结果吧
	cur = phead->next;
	while (cur)
	{
		printf("%d ", cur->val);
		cur = cur->next;
	}
}
int main()
{
	text1();
	return 0;
}

那么看结果

OK接下来看看优化的思路 头结点+双头插

对于这个例子

我们一第二条链表为基础对他进行插入操作

我们使用两个指针,分别指向两条链表的第一个位置cur1 cur2

如果第一个链表的值小于第二个链表的值那么尾插到此时第二个链表指针的前面

cur1->val<=cur2->val      

并且让第一个指针cur1=cur1->next;

当然这里只是大题思路不是代码

如果大于 cur1->val>cur2->val   

那么让cur2=cur2->next

在进行操作的时候,我们为了避免在第一个位置插入 ,从而加入了头指针

OK,看代码呗

struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {
    if(list1==NULL&&list2==NULL)
    return list1;
    else if(list1!=NULL&&list2==NULL)
    return list1;
    else if(list1==NULL&&list2!=NULL)
    return list2;
    struct ListNode*p1=list1;
    struct ListNode*p2=list2;
    struct ListNode*p2head=(struct ListNode*)malloc(sizeof(struct ListNode));
    p2head->next=p2;
    struct ListNode*front=p2head;
    while(p1&&p2)
    {
        if(p1->val<=p2->val)
        {
            //双指针中间插入
            //
            front->next=p1;
            struct ListNode*temp=p1;
            p1=p1->next;
            temp->next=p2;
            front=temp;
        }
        else
       {
        front=p2;
        p2=p2->next;
       }
    }
    //如果p2==null此时p1不为空,把p1接起来
    if(p2==NULL)
    front->next=p1;
    return p2head->next;


}

 第二题

现有一链表的头指针 ListNode* pHead,给一定值x,编写一段代码将所有小于x的结点排在其余结点之前,且不能改变原来的数据顺序,返回重新排列后的链表的头指针。

链表分割_牛客题霸_牛客网 (nowcoder.com)

ok

这个题目其实也可以暴力

但是

已经写了好多次暴力了,对吧

这一次可以说说思路

仍然可以使用数组,然后直接排序,不管x为多少,按从小到大的顺序,没有错

然后构建链表,这个题目就完了

挺暴力的吧

可以的

但是这个代码和之前大差不差

直接来看具体的思路

我们可以把一个链表分成两个链表,list1一个是大于等于x的,list2一个是小于x的

最后让list2连接list1

就完成任务了

思路看起来简单但是细节还是很多

我们在代码中有注释

class Partition {
public:
    ListNode* partition(ListNode* pHead, int x) {
    if(pHead==NULL&&pHead->next==NULL)
    return pHead;
    auto *head=(ListNode*)malloc(sizeof(ListNode));
    head->next=pHead;
    //头结点
    ListNode*front=head;
    ListNode*newlist=NULL;
    ListNode*newtail=NULL;
    ListNode*p=pHead;
    while(p)
    {
        if(p->val<x)
        {
            //在原有的链表上去除小于x的值
            ListNode*temp=p;
            p=p->next;
            temp->next=NULL;
            front->next=p;
            //对新的链表操作
            //小于x的值重新连成一个链表
            if(newlist==NULL)
            {
                newlist=newtail=temp;
            }
            else
            {
                newtail->next=temp;
                newtail=temp;
            }
        }
        else 
        {
            front=p;
            p=p->next;  
        }
    }
    //不要忘了呀,新的链表有可能为空呀,哎呦,搞了个半天
    if(newtail==NULL)
    return pHead;
    else
    newtail->next=head->next;
    return newlist;
    }
};

这个题目思路还是不难,继续努力

第三题

链表的回文结构_牛客题霸_牛客网 (nowcoder.com)

对于一个链表,请设计一个时间复杂度为O(n),额外空间复杂度为O(1)的算法,判断其是否为回文结构。

给定一个链表的头指针A,请返回一个bool值,代表其是否为回文结构。保证链表长度小于等于900。

1->2->2->1
返回:true

这个题目有难度了

所以我们可以通过画图来理解一下

思路,

我们可以找到中间的结点,把中间的结点逆置过来

然后一个指针从中间

另一个指针从开头

一直判断他们是否相等,就可以得到答案

看图呗

 OK,找中以及逆转链表之前已经有过讲解了

单链表的经典oj题(1)-CSDN博客

好吧,不懂可以去看

我们现在直接去看代码喽

 ListNode*middle(ListNode*A)
    {
        ListNode*slow=A;
        ListNode*fast=A;
        while(fast&&fast->next)
        {
            fast=fast->next->next;
            slow=slow->next;
        }
        return slow;
    }
    ListNode* revearse(ListNode*src)
    {
        ListNode* cur=src;
        ListNode* prev=NULL;
        while(cur)
        {
            ListNode* temp=cur->next;
            cur->next=prev;
            prev=cur;
            cur=temp;
        }
        return prev;
    }
    bool chkPalindrome(ListNode* A) {
        // write code here
        ListNode*cur=middle(A);
        ListNode* tail=revearse(cur);
        while(A&&tail)
        {
            if(tail->val!=A->val)
            return false;
            tail=tail->next;
            A=A->next;
        }
        return true;
    }

第四题

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

题目在这里

160. 相交链表 - 力扣(LeetCode)

OK

思路

 首先要判断他们是否是有相交节点

OK可以让他们走到最后一个节点

如果他们的最后一个节点相等,那他们就有相交节点,那么问题来了

怎么找到节点呢

要是知道两个链表的长度,再利用相对位移让他们距离相交节点的位移一样

最后让他们同时走,再判断,直到相等即可

OK

看代码

struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
    struct ListNode*A =headA;
    struct ListNode*B =headB;
    //这里最后一个节点没有加上,所以初始为1
    int sizeA=1;int sizeB=1;
    while(A->next)
    {
        A=A->next;
        sizeA++;
    }
    while(B->next)
    {
        B=B->next;
        sizeB++;
    }
    if(A!=B)return NULL;
    //通过假设,来简化代码
    //总之就是让A最长
    if(sizeA<sizeB)
    {
        A=headB;
        B=headA;
    }
    else
    {
        A=headA;
        B=headB;
    }
    int abs=sizeA-sizeB>0?sizeA-sizeB:sizeB-sizeA;
    //使他们里相交点的距离相等
    while(abs--)
    {
        A=A->next;
    }
    while(A!=B)
    {
        A=A->next;
        B=B->next;
    }
    return B;
}

第五题 

 141. 环形链表 - 力扣(LeetCode)

题目

给你一个链表的头节点 head ,判断链表中是否有环。

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos 不作为参数进行传递 。仅仅是为了标识链表的实际情况。

如果链表中存在环 ,则返回 true 。 否则,返回 false 。

示例 1:

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

OK

这个题目的思路很重要,我这里有两种做法

暴力求解

如果只要求求出题目,那么我们可不可以用一个数据来标明这个节点走过没有

  • -10^5 <= Node.val <= 10^5

当我们走过一个结点

直接给他加上一个10^6+10

+10是防止特殊情况,那么只要遍历一遍,走到某个节点,如果它大于

10^5证明我们走过这里,但是此时又回到了这里,此时可以判断为有环

缺点是破坏了链表

bool hasCycle(struct ListNode *head) {
    while(head)
    {
        if(head->val>1e5)
        return true;
        else
        {
            head->val+=1e6+10;
        }
        head=head->next;
    }
    return false;
}

这种办法还是挺有意思的不是吗?

OK

来看看不改变链表的结构的写法吧

这个还是要画图理解,并且这里还是涉及到了相对位置的概念

bool hasCycle(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)
        return true;
    }
    return false;

}

话不多说下一题

第六题

142. 环形链表 II - 力扣(LeetCode)

 这个题目,是上个题目的升级版

OK看题

给定一个链表的头节点  head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。

不允许修改 链表。

示例 1:

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

思路

大家看这里就是不允许修改链表了

这该如何是好

还是画图吧

这个题目更是一个物理的模型

OK,看代码吧

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

总结

今天的题还是挺多的,好好练吧

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Linux】进程的七大状态详解!

&#x1f490; &#x1f338; &#x1f337; &#x1f340; &#x1f339; &#x1f33b; &#x1f33a; &#x1f341; &#x1f343; &#x1f342; &#x1f33f; &#x1f344;&#x1f35d; &#x1f35b; &#x1f364; &#x1f4c3;个人主页 &#xff1a;阿然成长日记 …

如何查看centos7中Java在哪些路径下

在 CentOS 7 上&#xff0c;你可以通过几种方式查找安装的 Java 版本及其路径。以下是一些常用的方法&#xff1a; 1. 使用 alternatives 命令 CentOS 使用 alternatives 系统来管理同一命令的多个版本。你可以使用以下命令来查看系统上所有 Java 安装的配置&#xff1a; su…

C++动态内存管理:与C语言动态内存管理的差异之争

当你改错一行代码的时候&#xff1a; 当你想要重构别人的代码时&#xff1a; 目录 前言 一、C/C的内存分布 二、C/C语言中的动态内存管理 三、new与delete的实现原理 总结&#xff1a; 前言 在C中&#xff0c;内存管理是一个至关重要的主题。正确地管理内存可以避免内存泄…

上海AI Lab开源首个可替代GPT-4V的多模态大模型

与开源和闭源模型相比&#xff0c;InternVL 1.5 在 OCR、多模态、数学和多轮对话等 18 个基准测试中的 8 个中取得了最先进的结果。 上海AI Lab 推出的 InternVL 1.5 是一款开源的多模态大语言模型 (MLLM)&#xff0c;旨在弥合开源模型和专有商业模型在多模态理解方面的能力差距…

二、SPI协议

文章目录 总述1.SPI接口2. SPI工作模式3. SPI通信时序4. SPI协议 对比 UART协议&#xff08;上一篇文章刚介绍过uart协议&#xff0c;这里来对比一下&#xff09; 总述 SPI&#xff08;Serial Peripheral Interface&#xff09;是一种高速的、全双工、同步的串行通信总线&…

【影片欣赏】【指环王】【魔戒:国王归来 The Lord of the Rings: The Return of the King】

往期魔戒博客见&#xff1a; 【影片欣赏】【指环王】【魔戒&#xff1a;护戒使者 The Lord of the Rings: The Fellowship of the Ring】 【影片欣赏】【指环王】【魔戒&#xff1a;双塔奇谋 The Lord of the Rings: The Two Towers】 2004年发行&#xff0c;Special Extend…

副业兼职没那么难,视频号带货,1天稳定500,适合新手操作

向大家推荐一个项目&#xff1a;视频号书单号带货玩法。我已经实践了一段时间&#xff0c;并成功售出了1200多单&#xff0c;赚取了2万多元。这个项目表现相当出色&#xff0c;强烈推荐给大家&#xff01; 周周近财&#xff1a;让网络小白少花冤枉钱&#xff0c;赚取第一桶金 …

Linux vscode push报错fatal: Authentication failed

注意啊&#xff0c;Git基于密码的身份验证已经被删除了&#xff0c;所以这个报错发生时无论密码正确与否&#xff0c;以及参考比较旧的改bug教程&#xff0c;都没法提交。进入提示的网址&#xff0c;生成个人访问令牌就好了

200-500人规模工厂网络方案(中小企业网络)

一、方案概述 工厂一般有单独的弱电房&#xff0c;类似这种 里面采用的方案如下&#xff1a; 主要考虑有线、无线、财务、办公、访客等业务&#xff0c;便于维护管理和后续扩容 还需要 Wi-Fi覆盖零死角高速率&#xff0c;工作不卡顿 同时考虑AV反病毒、IPS入侵防御、用户准…

【MySQL数据库开发设计规范】之命名规范

欢迎点开这篇文章&#xff0c;自我介绍一下哈&#xff0c;本人姑苏老陈 &#xff0c;是一名JAVA开发老兵。 本文收录于 《MySQL数据库开发设计规范》专栏中&#xff0c;该专栏主要分享一些关于MySQL数据库开发设计相关的技术规范文章&#xff0c;定期更新&#xff0c;欢迎关注&…

python自动化生成ppt

使用Python和python-pptx创建PPT 在这篇博客中&#xff0c;我们将探讨如何使用Python库python-pptx来创建一个简单的PowerPoint演示文稿&#xff08;PPT&#xff09;。这个库允许我们以编程方式创建幻灯片、添加文本、图片、表格和自定义形状。 安装python-pptx 首先&#x…

智能助手上线,大模型提供云服务专属顾问

业务背景 在使用云服务的时候&#xff0c;当您遇到复杂问题&#xff0c;如配置、关联或计费方式不明确时&#xff0c;可能需要向客服提交工单进行技术沟通。在漫长的工作过程中&#xff0c;耗费了宝贵的时间和精力。 2024 年 4 月&#xff0c;百度智能云正式推出了融合文心大…

单调栈:(C++)

在题目的要求中&#xff0c;存在先进后出&#xff08;即在前面的数据需要遍历到后面的某一数据时才能确定计算值&#xff09;单调栈在一部分解题场景中避免了暴力解法的高时间复杂度问题&#xff0c;但是在做题过程中视情况而定&#xff0c;有些题目的最优解不一定使用单调栈&a…

【原创】springboot+mysql物资库存管理系统设计与实现

个人主页&#xff1a;程序猿小小杨 个人简介&#xff1a;从事开发多年&#xff0c;Java、Php、Python、前端开发均有涉猎 博客内容&#xff1a;Java项目实战、项目演示、技术分享 文末有作者名片&#xff0c;希望和大家一起共同进步&#xff0c;你只管努力&#xff0c;剩下的交…

利用AI提高内容生产效率的五个方案

目录 如何利用AI提高内容生产效率? ​编辑方向一&#xff1a;自动化内容生成 方向二&#xff1a;内容分发与推广 方向三&#xff1a;内容分析与优化 方向四&#xff1a;图像和音频处理 方向五&#xff1a;自动编辑和校对 如何利用AI提高内容生产效率? 简介&#xff1a…

车载电子电器架构 —— 应用软件开发(上)

车载电子电器架构 —— 应用软件开发(上) 我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 屏蔽力是信息过载时代一个人的特殊竞争力,任何消耗你的人和事,多看一眼都是你的不对。非必要不费力证明…

CellChat包文献介绍

Inference and analysis of cell-cell communication using CellChat - PubMed (nih.gov) 目录 在线数据 摘要 基础介绍 分析结果 1&#xff0c;概述 2&#xff0c;识别预测通路 3&#xff0c;连续的信号转导 4&#xff0c;预测空间共定位细胞群之间的关键信号转导事件…

企业活动想联系媒体报道宣传如何联系媒体?

在企业的宣传推广工作中,我曾经历过一段费事费力、效率极低的时期。那时,每当公司有重要活动或新项目需要媒体报道时,我便要一家家地联系媒体,发送邮件、打电话,甚至亲自登门拜访,只为求得一篇报道。然而,这样的过程充满了不确定性和挑战,时常让我感到焦虑和压力山大。 记得有一…

vue3专栏项目 -- 项目介绍以及准备工作

这是vue3TS的项目&#xff0c;是一个类似知乎的网站&#xff0c;可以展示专栏和文章的详情&#xff0c;可以登录、注册用户&#xff0c;可以创建、删除、修改文章&#xff0c;可以上传图片等等。 这个项目全部采用Composition API 编写&#xff0c;并且使用了TypeScript&#…

亚马逊产品排名提升全攻略:自养号测评干货

之前我们一同探讨了亚马逊产品排名的多种类型&#xff0c;现在让我们回到正题&#xff0c;探讨一下如何才能有效地提升产品排名&#xff0c;从而吸引并抓住平台的流量&#xff0c;最终将其转化为可观的销量。 首先&#xff0c;卖家必须明晰亚马逊的排名机制&#xff0c;它主要基…