博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
快慢指针在链表中的应用
阅读量:5796 次
发布时间:2019-06-18

本文共 2000 字,大约阅读时间需要 6 分钟。

快慢指针也是面试中的一个常考知识点,主要是链表的问题中应用较多。 

1. 判断链表是否存在环

设置两个指针(fast, slow),初始值都指向头,slow每次前进一步,fast每次前进二步,如果链表存在环,则fast必定先进入环,而slow后进入环,两个指针必定相遇。(当然,fast先行头到尾部为NULL,则为无环链表)程序如下:

01 int isExitsLoop(LinkList L) {
02 LinkList fast, slow;
03 fast = slow = L;
04 while (fast && fast->next)
05 {
06 slow = slow->next;
07 fast = fast->next->next;
08 if (slow == fast)
09 {
10 break;
11 }
12 }
13 return ((fast == NULL) || (fast->next == NULL));
14 }

找到环的入口点:找到第一次的相遇点,然后分别从表头,和相遇点,每次一步往下走,再次相遇就是环入口。

当fast若与slow相遇时,slow肯定没有走遍历完链表,而fast已经在环内循环了n圈(1<=n)。假设slow走了s步,则fast走了2s步(fast步数还等于s 加上在环上多转的n圈),设环长为r,则:

1 2s = s + nr
2 s= nr

设整个链表长L,入口环与相遇点距离为x,起点到环入口点的距离为a。

1 a + x = nr
2 a + x = (n – 1)r +r = (n-1)r + L - a
3 a = (n-1)r + (L – a – x)

(L – a – x)为相遇点到环入口点的距离,由此可知,从链表头到环入口点等于(n-1)循环内环+相遇点到环入口点,于是我们从链表头、与相遇点分别设一个指针,每次各走一步,两个指针必定相遇,且相遇第一点为环入口点。程序描述如下:

01 node* findLoopPort(node *head) {
02 node *fast, *slow;
03 fast = slow = head;
04 while (fast && fast->next) {
05 slow = slow->next;
06 fast = fast->next->next;
07 if (slow == fast) {
08 break;
09 }
10 }
11 if ((fast == NULL) || (fast->next == NULL)) {
12 return NULL;
13 }
14 slow = head;
15 while (slow != fast) {
16 slow = slow->next;
17 fast = fast->next;
18 }
19 return slow;
20 }

假设从链表开始的位置到环入口的距离为p,慢指针在环内走了的距离为c,假设慢指针一共走了n步,快指针一共做了2n步。

那么,有p+c=n

显然,从p+c这一点开始,慢指针再走n步,必然还会回到这个点。为啥?【因为经过了2n步,快指针到达了这一点,所以慢指针如果再走n步,也会到达这一点】

如果让快指针从链表头开始走n步,也会到达p+c这个位置,二者相遇的第一个地方,肯定是环入口。

567993-20160317225310537-989490854.png

图里,AB=p,BD=c,由于慢指针走了n步,快指针走了2n步,所以慢指针再走n步还是到达D点。
【DB=c只是说,慢指针在环内走了c这么远,不一定是不到一圈,也可能慢指针在环内走了几圈之后才到达D点,此时我们假定BD长度是这路径的总长为c
所以,得到如下解决办法:
在快慢指针相遇之后,让快指针重新指向链表头,慢指针还在p+c位置,然后二者同时走p步,每次走一步。走完之后二者相遇的位置就是环入口了。

如何快速找出未知长度单链表的中间节点?

普通方法:先遍历一遍单链表确定其长度L后,再从头节点出发循环L/2次即可查找到单链表的中间节点。该问题如果采用普通的方法虽然简单,但是查找效率太低。

快慢指针: 设置两个指针*fast、*slow都指向单链表的头节点,其中*fast的移动速度是*slow的2倍,当*fast指向末尾节点的时候,slow正好就在中间了,可以大大提高查找的效率。

当然,此时算法 还要考虑链表结点个数的奇偶数因素,当快指针移动x次后到达表尾(1+2x),说明链表有奇数个结点,直接返回慢指针指向的数据即可。如果快指针是倒数第二个结点,说明链表结点个数是偶数,这时 可以 实际情况 返回上中位数或下中位数或(上中位数+下中位数)的一半。

转载于:https://www.cnblogs.com/zhxshseu/p/5289875.html

你可能感兴趣的文章
skynet实践(8)-接入websocket
查看>>
系统版本判断
查看>>
关于Css选择器优先级
查看>>
My97DatePicker 日历插件
查看>>
0603 学术诚信与职业道德
查看>>
小点心家族第3位成员——楼层定位效果
查看>>
Knockout.Js官网学习(enable绑定、disable绑定)
查看>>
工厂模式家族
查看>>
hive基本操作与应用
查看>>
excel快捷键设置
查看>>
poj3692
查看>>
python之信号量【Semaphore】
查看>>
html5纲要,细谈HTML 5新增的元素
查看>>
Android应用集成支付宝接口的简化
查看>>
Hichart 资料收集
查看>>
C#开发微信门户及应用(12)-使用语音处理
查看>>
[分享]Ubuntu12.04安装基础教程(图文)
查看>>
数据集成之主数据管理(一)基础概念篇
查看>>
[Vim] 搜索模式(正则表达式)
查看>>
#HTTP协议学习# (二)基本认证
查看>>