链表中的一些问题——快慢指针
2016-11-03 13:44
232 查看
如果需要判断一个链表是否循环,或者是否带环,或是单向的链表求中位数、倒数第n个数,可以用到快慢指针以达到最简单的方法。
此种方法时间复杂度为O(n^2),效率比较低。下面介绍一种经典的、效率高一些的方法——快慢指针。
快慢指针的思路很简单,就好像两个人在赛跑,一个跑得快一个跑得慢。如果跑的是环形跑道,时间足够长的话,跑得慢的总会被套圈,即他俩的位置总有一个时间是冲个的;反之如果跑道是一条直线的话,俩人位置是永远不会重合的。
应用到这个问题中,可以设置两个指针p1,p2,p1每次向后走一步,p2每次向后走两步,若两个指针能够重合,就说明链表是带环的。
这种方法时间复杂度是O(n),效率会比第一种方法高不少。
判断链表是否带环
可以用两个指针p1,p2均指向头结点,p1每移动一次,p2遍历整个链表,查找是否有与p1地址相等的位置。//链表定义 struct ListNode { int val; struct ListNode *next; ListNode(int x) : val(x), next(NULL) {} };
bool doesExistLoop(ListNode *pHead) { ListNode *p1, *p2; p1 = p2 = pHead; while (p1->next) { while (p2->next) { p2 = p2->next; if (p2 == p1) return true; } p1 = p1->next; } return false; }
此种方法时间复杂度为O(n^2),效率比较低。下面介绍一种经典的、效率高一些的方法——快慢指针。
快慢指针的思路很简单,就好像两个人在赛跑,一个跑得快一个跑得慢。如果跑的是环形跑道,时间足够长的话,跑得慢的总会被套圈,即他俩的位置总有一个时间是冲个的;反之如果跑道是一条直线的话,俩人位置是永远不会重合的。
应用到这个问题中,可以设置两个指针p1,p2,p1每次向后走一步,p2每次向后走两步,若两个指针能够重合,就说明链表是带环的。
bool doesExistLoop(ListNode *pHead) { ListNode *fast, *slow; fast = slow = pHead; while (fast) { slow = slow->next; fast = fast->next->next; if (slow == fast) return true; } return false; }
这种方法时间复杂度是O(n),效率会比第一种方法高不少。
如果链表带环,如何找环的入口
思路如下:先利用上边寻找环的方法,当快慢指针相遇的时候,一个指针从头开始,另一个从相遇的地方开始,两个同步走,下一次相遇的地方一定是入口(不知道什么原理,但是亲自试了几个后发现真是……)ListNode* findLoopPort(ListNode *pHead) { ListNode *fast, *slow; fast = slow = pHead; while (fast->next) { slow = slow->next; fast = fast->next->next; if (fast == slow) break; } if (fast == NULL&&fast->next == NULL) return NULL; while (slow != fast) { slow = slow->next; fast = fast->next; } return fast; }
在有序链表中寻找中位数
若不借助计数器变量实现查找中位数的功能,快慢指针也是最好的选择。让快指针的速度保持为慢指针的两倍,这样当快指针达到链表最后的时候,慢指针正好到达链表的中间。注意判断链表有奇数个节点还是偶数个节点,若奇数个节点,则慢指针的值就是所求;若偶数个节点,则慢指针和慢指针下一个的值的平均数就是所求。int findMiddle(ListNode *pHead) { ListNode *fast, *slow; fast = slow = pHead; while (fast) { if (fast->next == NULL) return slow->val; else if (fast->next == NULL&&fast->next->next == NULL) return (slow->val + slow->next->val) / 2; else { fast = fast->next->next; slow = slow->next; } } }
返回链表中倒数第n个数
保持快指针的速度比慢指针快n即可。ListNode* lastButOne(ListNode *pHead) { ListNode *fast, *slow; if (!pHead || !pHead->next || !pHead->next->next) return NULL; fast = pHead->next->next; slow = pHead; while (!fast->next) { fast = fast->next->next; slow = slow->next; } return slow;
相关文章推荐
- 关于链表的一些问题
- 单链表基本操作以及一些常见的面试问题
- 由链表而想到的一些问题[讨论]
- iOS 单链表算法的一些问题
- 关于遇到过链表问题的一些总结
- 关于链表的一些问题
- 单链表中的一些经典问题--约瑟夫环,逆序,查找,复杂链表复制,链表带环问题
- 关于链表操作一些有趣的问题!
- 数据结构链表的一些的问题
- 链表的一些简单操作(修复里上一篇链表操作问题)
- (链表)链表的一些合并问题
- 单链表中一些经典的问题-->约瑟夫环,链表逆序,查找链表结点...(上)
- 链表的一些常见笔试面试问题总结及代码
- 环链表的一些问题
- 关于链表的一些经典问题以及相关面试题
- 【数据结构】链表的一些问题
- [转载]VC 和 MFC 的一些常见问题
- 关于ASP.NET在IIS一些问题的经验总结
- 面试时要注意的一些问题
- C语言程序设计的一些基本问题