当前位置:网站首页>判断链表是否有环
判断链表是否有环
2022-07-30 12:51:00 【qq_25427995】
当链表存在环时,通过直接遍历链表无法知道是否存在环。假设我们可以修改链表结构的话,可以在链表里加入访问的标记,当下一个节点已经被访问过就说明存在环。
方法一、穷举遍历
首先从头节点开始,依次遍历单链表的每一个节点。每遍历到一个新节点,就从头节点重新遍历新节点之前的所有节点,用新节点ID和此节点之前所有节点ID(即重新遍历len-1步)依次作比较。如果发现新节点之前的所有节点当中存在相同节点ID,则说明该节点被遍历过两次,链表有环;如果之前的所有节点当中不存在相同的节点,就继续遍历下一个新节点,继续重复刚才的操作。
例如这样的链表:A->B->C->D->B->C->D, 当遍历到节点D的时候,我们需要比较的是之前的节点A、B、C,不存在相同节点。这时候要遍历的下一个新节点是B,B之前的节点A、B、C、D中恰好也存在B,因此B出现了两次,判断出链表有环。
struct ListNode {
int val;
ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};
bool detectCycle(ListNode *head) {
ListNode *tem = head,*temp;
int len = 0;
while(tem){
*temp = head;
for(int i=0;i<len;i++)
{
if(temp==tem) return true;
temp = temp->next;
}
len++;
tem = tem->next;
}
return false;
}
时间复杂度为(n^2),空间复杂度为O(1)。
方法二、哈希表/set 缓存
哈希表:首先创建一个以节点ID为键的HashSet集合,用来存储曾经遍历过的节点。然后同样是从头节点开始,依次遍历单链表的每一个节点。每遍历到一个新节点,就用新节点和HashSet集合当中存储的节点作比较,如果发现HashSet当中存在相同节点ID,则说明链表有环,如果HashSet当中不存在相同的节点ID,就把这个新节点ID存入HashSet,之后进入下一节点,继续重复刚才的操作。
set集合:还可以用 set 遍历链表,把节点放入set里,每次访问下个节点时,如果set长度不变,则跳出,说明有环。否则set长度+1,继续遍历。
ListNode *detectCycle(ListNode head) {
set<ListNode node> s;
while(head){
if(s.size()==s.push(head)) return true;
head = head->next();
}
return false;
}
该方法时间复杂度是O(N),空间复杂度上因为需要额外等数量的存储空间,所以空间复杂度是O(n)。
方法三、快慢指针
首先创建两个指针1和2(在java里就是两个对象引用),同时指向这个链表的头节点。然后开始一个大循环,在循环体中,让指针1每次向下移动一个节点,让指针2每次向下移动两个节点,然后比较两个指针指向的节点是否相同。如果相同,则判断出链表有环,如果不同,则继续下一次循环。
例如链表A->B->C->D->B->C->D,两个指针最初都指向节点A,进入第一轮循环,指针1移动到了节点B,指针2移动到了C。第二轮循环,指针1移动到了节点C,指针2移动到了节点B。第三轮循环,指针1移动到了节点D,指针2移动到了节点D,此时两指针指向同一节点,判断出链表有环。
ListNode *detectCycle(ListNode *head) {
ListNode *tem,*temp;
tem = temp = head;
while(tem && temp){
tem = tem->next;
temp = temp->next->next;
if(tem==temp) return true;
}
return false;
}
该方法时间复杂度是O(N),空间复杂度上因为需要额外等数量的存储空间,所以空间复杂度是O(1)。
链表中环的入口节点 - 力扣(LeetCode) (leetcode-cn.com)
扩展z何判断两个单链表是否相交,以及相交点
方法一、直接法
直接判断第一个链表的每个结点是否在第二个链表中,时间复杂度为O(len1*len2),耗时很大。
方法二、利用计数
如果两个链表相交,则两个链表就会有共同的结点;而结点地址又是结点唯一标识。因而判断两个链表中是否存在地址一致的节点,就可以知道是否相交了。可以对第一 个链表的节点地址进行hash排序,建立hash表,然后针对第二个链表的每个节点的地址查询hash表,如果它在hash表中出现,则说明两个链表有共 同的结点。这个方法的时间复杂度为:O(max(len1+len2);但同时还得增加O(len1)的存储空间存储哈希表。这样减少了时间复杂度,增加 了存储空间。
以链表节点地址为值,遍历第一个链表,使用Hash保存所有节点地址值,结束条件为到最后一个节点(无环)或Hash中该地址值已经存在(有环)。
再遍历第二个链表,判断节点地址值是否已经存在于上面创建的Hash表中。
这个方面可以解决题目中的所有情况,时间复杂度为O(m+n),m和n分别是两个链表中节点数量。
方法三、利用有环链表思路
对于两个没有环的链表相交于一节点,则在这个节点之后的所有结点都是两个链表所共有的。如果它们相交,则最后一个结点一定是共有的,则只需要判断最后一个结点是否相同即可。时间复杂度为O(len1+len2)。对于相交的第一个结点,则可求出两个链表的长度,然后用长的减去短的得到一个差值 K,然后让长的链表先遍历K个结点,然后两个链表再开始比较。
参考
原文链接:https://blog.csdn.net/u010983881/article/details/78896293
边栏推荐
猜你喜欢
dbaplus丛书丨《MySQL DBA工作笔记》限量签名版来了!
How to display an Excel table in the body of an email?
北上广线下活动丨年底最不可错过的技术聚会都齐了
最基础01/完全背包
展厅全息投影所具备的三大应用特点
常见的云计算安全问题以及如何解决
js 构造函数 return 非空对象,其实例化的对象在原型上的差异
PyQt5快速开发与实战 8.6 设置样式
Beijing, Shanghai and Guangzhou offline events丨The most unmissable technology gatherings at the end of the year are all gathered
企业如何成功完成云迁移?
随机推荐
Analysis of AI recognition technology and application scenarios of TSINGSEE intelligent video analysis gateway
13-GuliMall Basics Summary
dolphinscheduler simple task definition and complex cross-node parameter transfer
Anaconda\Scripts\pip-script.py is not present ? 解决方案
初级永磁直线电机双动子电流镜像容错控制
13-GuliMall 基础篇总结
Mysql batch insert transaction unique key repeated processing
多表联查的学习
重建丢失的数据
第42讲:Scala中泛型类、泛型函数、泛型在Spark中的广泛应用
DeFi 巨头进军 NFT 领域 用户怎么看?
Heshu Group: Make smart cities smarter and make real life better
元宇宙的六大支撑技术
双击Idea图标打不开——解决办法
域名抢注“卷”到了表情包?ENS逆势上涨的新推力
R语言时间序列数据算术运算:使用log函数将时间序列数据的数值对数化(平方、开平方、指数化等函数类似使用)
curl 执行脚本时传递环境变量与参数
C语言学习练习题:汉诺塔(函数与递归)
MySQL查询性能优化
Beijing, Shanghai and Guangzhou offline events丨The most unmissable technology gatherings at the end of the year are all gathered