单链表环相关

一、单链表问题

1️⃣给一个单链表,判断是否存在环。
2️⃣如果存在环,找出环的入口点。
3️⃣如果存在环,求出环上节点的个数。
4️⃣如果存在环,求出链表的长度。
5️⃣如果存在环,求出环上距离任意一个节点最远的点(对面节点)。
6️⃣如何判断两个无环链表是否相交。如果相交,求出第一个相交的节点。

二、判断时候有环(链表头指针为head)

1️⃣“快慢指针”法。就是有两个指针 fast 和 slow,开始的时候两个指针都指向链表头head,然后在每一步操作中 slow 向前走一步即:slow = slow->next,而 fast 每一步向前走两步即:fast = fast->next->next。由于 fast 要比 slow 移动的快,如果有环,fast 一定会先进入环,而 slow 后进入环。当两个指针都进入环之后,经过一定步数的操作之后,二者一定能够在环上相遇,并且此时 slow 还没有绕环一圈(相当于田径跑道上套圈的逻辑)。如图:

当 slow 刚进入环时每个指针可能处于上面的情况,接下来 slow 和 fast 分别向前走即:

if (slow != NULL && fast->next != NULL) { 
         slow = slow -> next ; 
         fast = fast -> next -> next ;
}

也就是说,slow 每次向前走一步,fast 向前追了两步,因此每一步操作后 fast 到 slow 的距离缩短了1步,这样继续下去就会使得两者之间的距离逐渐缩小:...、5、4、3、2、1、0 -> 相遇。又因为在同一个环中 fast 和 slow 之间的距离不会大于换的长度,因此到二者相遇的时候 slow 一定还没有走完一周(或者正好走完以后,这种情况出现在开始的时候 fast 和 slow 都在环的入口处)。

typedef struct node{ 
    char data ; 
    node * next ; 
}Node; 
bool exitLoop(Node *head) 
{ 
    Node *fast, *slow ; 
    slow = fast = head ; 
   
    while (slow != NULL && fast -> next != NULL) 
    { 
        slow = slow -> next ; 
        fast = fast -> next -> next ; 
        if (slow == fast) 
            return true ; 
    } 
    return false ; 
}

2️⃣使用 Set 做标记,一次遍历,当发现这个节点被标记了,那么说明走到了重复的点,也就说明有环了。

三、找出环的入口点

从上面的分析知道,当 fast 和 slow 相遇时,slow 还没有走完链表,假设 fast 已经在环内循环了n(1<= n)圈。此时 slow 走了s步,则 fast 走了2s步,又由于 fast 走过的步数为s + n*r(s + 在环上多走的n圈),则有等式:
2*s = s + n*r--->②s = n*r
假设起点到入口点的距离是a,入口点到相遇点的距离是x,则有:
a + x = s = n*r--->④a = n*r - x

结合④以及上图可以看出,从链表起点 head 开始到入口点的距离a,与从入口点到 slow 和 fast 的相遇点的距离x相等。【分析】现让一指针p1从链表起点 head 开始遍历,指针p2从相遇点开始遍历,且p1和p2移动步长均为1。则当p1移动a步即到达环的入口点,由④可知,此时p2也已移动a步即nr - x步。由于p2是从相遇点开始移动,故p2移动nr步是回到了相遇点,再退x步则是到了环的入口点。也即,当p1移动a步第一次到达环的入口点时,p2也恰好到达了该入口点。

因此可以用指针(ptr1,prt2),同时从 head 与 slow 和 fast 的相遇点出发,每一次操作走一步,直到 ptr1 == ptr2,此时的位置也就是入口点。

Node* findLoopStart(Node *head) 
{ 
    Node *fast, *slow ; 
    slow = fast = head ; 
   
    while (slow != NULL && fast -> next != NULL) 
    { 
        slow = slow -> next ; 
        fast = fast -> next -> next ; 
        if (slow == fast) break ; 
    } 
    if (slow == NULL || fast -> next == NULL) return NULL ; //没有环,返回NULL值 
   
    Node * ptr1 = head ; //链表开始点 
    Node * ptr2 = slow ; //相遇点 
    while (ptr1 != ptr2)  
    { 
        ptr1 = ptr1 -> next ; 
        ptr2 = ptr2 -> next ; 
    } 
    return ptr1 ; //找到入口点 
} 

四、求环上节点的个数

1️⃣记录下相遇节点存入临时变量 tempPtr,然后让 slow (或者 fast 也行)继续向前走slow = slow -> next,一直到slow == tempPtr,此时经过的步数就是环上节点的个数。

2️⃣从相遇点开始 slow 和 fast 继续按照原来的方式向前走slow = slow -> next; fast = fast -> next -> next;直到二者再次相遇,此时经过的步数就是环上节点的个数 。

对于第二种思路,可以这样想,结合上面的分析,fast 和 slow 每一次操作都会使得两者之间的距离较少1。可以把两者相遇的时候看做两者之间的距离正好是整个环的长度r。因此,当再次相遇的时候所经过的步数正好是环上节点的数目。

五、求出链表的长度

链表长度L = 起点到入口点的距离 + 环的长度r

六、求出环上距离任意一个节点最远的点(对面节点)

如图,点1和4、点2和5、点3和6分别互为“对面节点”,也就是环上最远的点,要求是怎么求出环上任意一个点的最远点。

对于环上任意的一个点 ptr0,要找到它的“对面点”,可以这样思考:同样使用快慢指针法,让 slow 和 fast 都指向 ptr0,每一步都执行与上面相同的操作(slow 每次跳一步,fast 每次跳两步),当fast = ptr0或者fast = prt0->next的时候 slow 所指向的节点就是 ptr0 的”对面节点“。

为什么是这样呢?可以这样分析:

如图,把环从 ptr0 处展开,展开后可以是无限长的(如上在6后重复前面的内容)。由于 slow 移动的距离永远是 fast 的一半,因此当 fast 遍历完整个环长度r个节点的时候 slow 正好遍历了r/2个节点,也就是说此时正好指向距离 ptr0 最远的点。

七、如何判断两个无环链表是否相交,如果相交,求出第一个相交的节点

做个转化:假设有两个链表 listA 和 listB,如果两个链表都无环,并且有交点,那么可以让其中一个链表(比如listA)的尾节点连接到其头部,这样在 listB 中就一定会出现一个环。因此这个问题就转化成了问题1️⃣和2️⃣。看看下图就会明白了:
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,634评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,951评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,427评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,770评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,835评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,799评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,768评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,544评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,979评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,271评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,427评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,121评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,756评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,375评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,579评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,410评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,315评论 2 352