链表常见面试题三:解决链表带环问题
2016-04-11 20:04
731 查看
问题1:判断链表是否带环
解题思路:
用两个指针,快指针一次走两步,慢指针一次走一步,如果两指针相遇,那么链表带环,若两指针不相遇,则链表不带环。
问题2:若链表带环则求环的长度
解题思路:
面试题1已经判断过链表带环,且返回两指针相遇节点,求环长度时我们可以让一个指针从相遇节点处开始遍历,当再次回到相遇节点时,它走过的步数就是环的长度。
问题3:获取环入口点
解题思路:
方法一:假设上图是一个单链表,两指针走到相遇节点时,慢指针走了x+y步,快指针走了x+y+nl步,(l为环的长度),由于快指针速度是慢指针速度的一倍,那么就有以下的等式:
(x+y)*2=x+y+nl;
化解可得:
x=nl-y;
那解题时我们可以用两个指针,一个指针从链表的开始位置走,另一个指针从相遇的节点处开始走,也就是y,两个指针相遇的节点就是入口点。
方法二:
将相遇的节点处断开,转化为两条链表相交求交点问题,两个指针meet和Entry分别遍历到链表尾,记录两链表的长度len_l1和len_l2,然后让较长的链表先走len=|len_l1 - len_l2|步,然后两指针一起走,直到两指针相遇,相遇的节点就是链表的交点,即环的入口点。
pLinkNode _GetCycleEntryNode(pList head, pLinkNode MeetNode)//链表带环转化为链表相交问题获取入口
解题思路:
用两个指针,快指针一次走两步,慢指针一次走一步,如果两指针相遇,那么链表带环,若两指针不相遇,则链表不带环。
pLinkNode CheckCycle(pList head) { pLinkNode fast = head; pLinkNode slow = head; while (fast && fast->next) { fast = fast->next->next; slow = slow->next; if (fast == slow) { return slow; 两指针相遇,链表带环,返回相遇点 } } return NULL; //若两指针不相遇,返回null,链表不带环 }
问题2:若链表带环则求环的长度
解题思路:
面试题1已经判断过链表带环,且返回两指针相遇节点,求环长度时我们可以让一个指针从相遇节点处开始遍历,当再次回到相遇节点时,它走过的步数就是环的长度。
int GetCircleLength(pLinkNode meet) { pLinkNode cur = meet; int count = 0; do { cur = cur->next; count++; } while (cur != meet); return count; }
问题3:获取环入口点
解题思路:
方法一:假设上图是一个单链表,两指针走到相遇节点时,慢指针走了x+y步,快指针走了x+y+nl步,(l为环的长度),由于快指针速度是慢指针速度的一倍,那么就有以下的等式:
(x+y)*2=x+y+nl;
化解可得:
x=nl-y;
那解题时我们可以用两个指针,一个指针从链表的开始位置走,另一个指针从相遇的节点处开始走,也就是y,两个指针相遇的节点就是入口点。
pLinkNode GetCycleEntryNode(pList head, pLinkNode MeetNode) { pLinkNode Entry= head; pLinkNode meet = MeetNode; while (meet != Entry) { Entry = Entry->next; meet = meet->next; } return Entry; }
方法二:
将相遇的节点处断开,转化为两条链表相交求交点问题,两个指针meet和Entry分别遍历到链表尾,记录两链表的长度len_l1和len_l2,然后让较长的链表先走len=|len_l1 - len_l2|步,然后两指针一起走,直到两指针相遇,相遇的节点就是链表的交点,即环的入口点。
pLinkNode _GetCycleEntryNode(pList head, pLinkNode MeetNode)//链表带环转化为链表相交问题获取入口
{ pLinkNode Entry = head; pLinkNode meet = MeetNode->next; int len_head = 0; int len_meet = 0; int len = 0; while (Entry != MeetNode) //求链表长度 { len_head++; Entry = Entry->next; } while (meet != MeetNode)//求链表长度 { len_meet++; meet = meet->next; } Entry = head; meet = MeetNode->next; if (len_head > len_meet) { len = len_head - len_meet; while (len--) { Entry = Entry->next; }//较长链表先走len=|len_l1 - len_l2|步 } else { len = len_meet - len_head; while (len--) { meet = meet->next; }//较长链表先走len=|len_l1 - len_l2|步 } while (meet != Entry) { Entry = Entry->next; meet = meet->next; } //两指针同时走,相遇节点就是环入口点 return Entry; }
相关文章推荐
- 链表常见面试题二:约瑟夫环
- 链表常见面试题一:基本问题
- 剑指offer-面试题38:数字在排序数组中出现的次数
- 找出一个整数数组中的第二大数
- 面试题77:前缀、中缀、后缀表达式的相互转换
- 面试题:对1、2、2、3、4、5六个数字进行排列组合
- 程序员遇到Bug时的30个反应
- 项目死沉半年,面试失败根源
- Java常用排序算法+程序员必须掌握的8大排序算法+二分法查找法
- 面试积累 简历添加
- 为大龄程序员找出路,破解程序员是一碗青春饭之迷
- 面试问题集锦
- 最基础、最全面的iOS面试题目
- 那些著名或非著名的iOS面试题-后编
- 深入详解多线程第一篇_多线程笔试面试题汇总
- 面试前——做好准备
- LeetCode(45)-Bulls and Cows
- 前端开发面试题及答案
- 71道经典Android面试题和答案,重要知识点都包含了
- 【转载】 Java线程面试题 Top 50