当前位置: 首页 > news >正文

链表OJ习题(2)

一. 牛客网 链表的回文结构

https://www.nowcoder.com/practice/d281619e4b3e4a60a2cc66ea32855bfa

思路

1、偶数情况:

2、奇数情况:

代码实现

class PalindromeList {public://1.找中间节点ListNode* middleNode(ListNode* head) {//快慢指针ListNode* fast, * slow;fast = head;slow = head;while (fast != NULL && fast->next != NULL) {slow = slow->next;fast = fast->next->next;}return slow;}//2.翻转以中间节点为头的链表ListNode* reverseList(ListNode* head) {if (head == NULL) {return head;}ListNode* n1, *n2, *n3;n1 = NULL;n2 = head;n3 = n2->next;while (n2) {n2->next = n1;n1 = n2;n2 = n3;if (n3)n3 = n3->next;}return n1;}bool chkPalindrome(ListNode* A) {//1.找中间节点ListNode* mid = middleNode(A);//2.翻转以中间节点为头的链表ListNode* right = reverseList(mid);//3.遍历原链表和反转后的链表,比较节点的值是否相等ListNode* left = A;while (right) {if (left->val != right->val) {return false;}left = left->next;right = right->next;}return true;}
};

二. leetcode 160 相交链表

https://leetcode.cn/problems/intersection-of-two-linked-lists/description/

思路

共存在三种相交情况(一定会在末尾相遇):

1、在末尾处相交

2、在起点处相交

           

3、在中间处相交

不存在以下这种情况:因为 c1 只有1个next指针,只能指向一个节点

代码实现

typedef struct ListNode ListNode;
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {ListNode* pa=headA;ListNode* pb=headB;int sizeA=0,sizeB=0;while(pa){sizeA++;pa=pa->next;}while(pb){sizeB++;pb=pb->next;}//求长度差int gap=abs(sizeA-sizeB);//求绝对值//假设法ListNode* longList=headA;ListNode* shortList=headB;if(sizeA<sizeB){longList=headB;shortList=headA;}while(gap--){longList=longList->next;}while(shortList){if(longList==shortList){return shortList;}shortList=shortList->next;longList=longList->next;}return NULL;
}

三. 环形链表 |

思路

https://leetcode.cn/problems/linked-list-cycle/description/

slow⼀次走⼀步,fast⼀次走2步,fast先进环,假设slow也走完⼊环前的距离,准备进环,此时fast 和slow之间的距离为N,接下来的追逐过程中,每追击⼀次,他们之间的距离缩小1步

追击过程中fast和slow之间的距离变化:

因此,在带环链表中慢指针走⼀步,快指针走两步最终⼀定会相遇。

思考2:快指针⼀次走3步,走4步,...n步⾏吗?

答案是可以的,有兴趣的同学可以自行推导一下,这里就不再赘述了

代码实现

typedef struct ListNode ListNode;
bool hasCycle(struct ListNode *head) {if(head==NULL){return false;}//快慢指针ListNode*slow,*fast;slow=fast=head;while(fast!=NULL && fast->next!=NULL){slow=slow->next;fast=fast->next->next;//如果快指针与慢指针相遇,那么一定有环if(slow==fast){return true;}}return false;
}

四. 环形链表 ||

https://leetcode.cn/problems/linked-list-cycle-ii/description/

思路

说明:
H为链表的起始点,E为环入口点,M与判环时候相遇点
设:
环的⻓度为R,H到E的距离为L,E到M的距离为 X ,则:M到E的距离为 R-X

在判环时,快慢指针相遇时所⾛的路径⻓度:
fast: L+X + nR 
slow:L+X 

注意:
1.当慢指针进⼊环时,快指针可能已经在环中绕了n圈了,n⾄少为1
因为:快指针先进环⾛到M的位置,,最后⼜在M的位置与慢指针相遇
2.慢指针进环之后,快指针肯定会在慢指针⾛⼀圈之内追上慢指针
因为:慢指针进环后,快慢指针之间的距离最多就是环的⻓度,⽽两个指针在移动时,每次它们⾄今
的距离都缩减⼀步,因此在慢指针移动⼀圈之前快,指针肯定是可以追上慢指针的,⽽快指针速度是慢指针的两倍,因此有如下关系是:
2 * (L+X)=L+X+nR
L+X=nR
L=nR-X
L = (n-1)R+(R-X)
(n为1,2,3,4......,n的大小取决于环的大小,环越小n越⼤)

因为R为环的周长,所以无论前面的系数是多少,最终都是环周长的整数倍
所以:
L=R-X 
即:⼀个指针从链表起始位置运行,⼀个指针从相遇点位置绕环,每次都走⼀步,两个指针最终会在入口点的位置相遇

代码实现

typedef struct ListNode ListNode;
struct ListNode *detectCycle(struct ListNode *head) {ListNode* slow=head;ListNode* fast=head;while(fast && fast->next){slow=slow->next;fast=fast->next->next;if(slow==fast){//带环//头节点到入环节点的距离 == 相遇节点到入环节点的距离ListNode* pcur=head;//这里就再一次用到了head,所以之前不能用head遍历while(pcur!=slow){pcur=pcur->next;slow=slow->next;}return pcur;}}return NULL;
}

五. 随机链表的复制

https://leetcode.cn/problems/copy-list-with-random-pointer/description/

思路

1、在原链表基础上拷贝节点并插入到原链表中

2、设置 radom 指针(注:这里未将所有的radom指针画完)

3、断开与原链表的链接(注:这里未将所有的radom指针画完)

代码实现

/*** 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));if (newnode == NULL) {return NULL; // 处理内存分配失败的情况}newnode->val = x;newnode->next = newnode->random = NULL;return newnode;
}//在原链表基础上拷贝节点并插入到原链表中
void AddNode(Node* head) 
{Node* pcur=head;while(pcur){Node* newnode=BuyNode(pcur->val);Node* next=pcur->next;newnode->next=next;pcur->next=newnode;pcur=next;}
}//设置radom
void setRandom(Node* head)
{Node* pcur=head;while(pcur){Node* copy=pcur->next;if(pcur->random)copy->random=pcur->random->next;pcur=copy->next;}
}struct Node* copyRandomList(struct Node* head) {if(head==NULL){return head;}//在原链表基础上拷贝节点并插入到原链表中AddNode(head);//设置radomsetRandom(head);//断开链表Node* pcur=head;Node* copyHead,* copyTail;copyHead=copyTail=pcur->next;while(copyTail->next){pcur=copyTail->next;copyTail->next=pcur->next;copyTail=copyTail->next;}return copyHead;
}

总结

本篇博客深入解析了经典的链表OJ习题,旨在帮助读者掌握链表操作的核心技巧与解题思路,通过对典型例题的剖析和画图理解,助你巩固数据结构基础。

如果大家在练习中发现新的解题角度,或是有没搞懂的知识点,欢迎在评论区留言讨论。后续我也会持续更新数据结构相关的 OJ 解析,咱们一起在刷题中夯实基础,稳步进阶!

http://www.xdnf.cn/news/1366777.html

相关文章:

  • 操作系统中,进程与线程的定义与区别
  • 似然函数对数似然函数负对数似然函数
  • Ant Design for UI 选择下拉框
  • BIO、NIO 和 AIO
  • 2025.8.25回溯算法-集合
  • Typora + PicList + Gitee 图床完整配置教程
  • 【ElasticSearch】json查询语法和可用的客户端
  • ESP32开发WSL_VSCODE环境搭建
  • Mysql系列--8、索引
  • Java延迟任务实现方案详解:从DelayQueue到实际应用
  • 2.3零基础玩转uni-app轮播图:从入门到精通 (咸虾米总结)
  • 【Docker基础】Docker-compose进阶配置:健康检查与服务就绪
  • K8s Pod驱逐机制详解与实战
  • C++ extern 关键字面试深度解析
  • 开源 C++ QT Widget 开发(六)通讯--TCP调试
  • 安全合规:AC(上网行为安全)--下
  • vue 一键打包上传
  • Genymotion 虚拟机如何安装 APK?(ARM 插件安装教程)
  • ICCV 2025|TRACE:无需标注,用3D高斯直接学习物理参数,从视频“预知”未来!
  • 二、添加3D形状
  • More Effective C++ 条款07:不要重载、和,操作符
  • 【系统架构设计师】数据库设计(一):数据库技术的发展、数据模型、数据库管理系统、数据库三级模式
  • 审核问题——首次进入APP展示隐私政策弹窗
  • 大模型(一)什么是 MCP?如何使用 Charry Studio 集成 MCP?
  • 深分页实战
  • 计算机网络:HTTP、抓包、TCP和UDP报文及重要概念
  • GPT5的Test-time compute(测试时计算)是什么?
  • Legion Y7000P IRX9 DriveList
  • HTTP 与 HTTPS 深度解析:从原理到实际应用
  • 链表OJ习题(1)