当前位置:网站首页>判断链表是否有环
判断链表是否有环
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
边栏推荐
- Dry Goods Sharing: Various Implementation Methods of Bean Management Factory with Great Use of Small Skills
- These critical programs are missing or too old: ma
- How to migrate the device data connected by RTSP of EasyCVR platform to EasyNVR?
- curl 执行脚本时传递环境变量与参数
- 13-GuliMall Basics Summary
- 力扣——15. 三数之和
- 智能指针实现猜想
- CMake库搜索函数居然不搜索LD_LIBRARY_PATH
- 关于香港高防IP需要关注的几个问题
- datax开启hana支持以及dolphinscheduler开启datax任务
猜你喜欢
随机推荐
434. 字符串中的单词数
【ASP.NET Core】选项类的依赖注入
常见的云计算安全问题以及如何解决
Jackson 的JAR包冲突问题
How to solve the problem that the page does not display the channel configuration after the EasyNVR is updated to (V5.3.0)?
Hand tearing read-write lock performance test
初级永磁直线电机双动子电流镜像容错控制
Decoding Redis' most overlooked high CPU and memory usage issues
dolphinscheduler单机化改造
【23考研】408代码题参考模板——链表
DeFi 巨头进军 NFT 领域 用户怎么看?
These critical programs are missing or too old: ma
Markdown 1 - 图文音视频等
[PostgreSQL] - explain SQL分析介绍
ES6 Set与Map是什么,如何使用
grep时排除指定的文件和目录
使用百度EasyDL实现明厨亮灶厨师帽识别
dbaplus丛书丨《MySQL DBA工作笔记》限量签名版来了!
EasyNVR更新版本至(V5.3.0)后页面不显示通道配置该如何解决?
私有化部署的即时通讯平台,为企业移动业务安全保驾护航









