首页 > 编程知识 正文

双指针 快慢指针,快慢指针证明

时间:2023-05-04 06:34:06 阅读:195042 作者:1481

所谓「快慢指针」是指设定两个指针,其中快的指针的移动速度是慢的指针的移动速度的两倍;“快慢指针”方法主要用来解决两类问题,即“判断一个链表是否为循环链表”以及“寻找一个有序链表的中位数”

针对该算法思想,还可以用来计算“循环结”的具体位置(在本文最后讲解)

判断一个链表是否为循环链表

该算法可以判断任何形式的循环链表(包括“6”形的链表)

如果仅仅是头尾相接的循环链表(单向循环链表)倒也简单

bool isCLinkList(List *Head){ List *p = Head; while(p){ p = p->next; if(p == Head){ return true; } } return false;}

但是……想想双向循环链表什么的(上面的代码是不兼容的)
甚至对应像“6”形的循环就会陷入无限死循环(想想都怕)!

bool isCLinkList(List *head){ if(!head){ return false; } List *p1 = head; List *p2 = p1->next; while(p1){ while(p2){ if(p2 == p1){ return true; } p2 = p2->next; } p1 = p1->next; } return false;}

以上……是一种十分恶心丑陋的算法,因为它对于每个外层循环都要在内层循环遍历之后的元素,效率很低

是时候show出「快慢指针」方法了:

bool IsCLinkList(List *head){ if(!head){ return false; } List *fast, *slow; fast = slow = head; while(1){ if(!fast || !fast->next){ return false; }else if(fast == slow || fast->next==slow){ return true; }else{ slow = slow->next; fast = fast->next->next; } }}

或者这样写:

int IsCLinkList(List *head) { List *fast, *slow; fast = slow = head; while (fast && fast->next) { slow = slow->next; fast = fast->next->next; if (slow == fast) { break; } } return ((fast == NULL) || (fast->next == NULL));}

该算法的时间复杂度为O(n),空间复杂度为O(1)

求一个有序链表的值域的中位数

该算法可以不借助计数器实现求解中位数(Amazing!)

快慢指针方法还可以用来干这个!(棒)

原理是:快指针的移动速度是慢指针移动速度的2倍,因此当快指针到达链表尾时,慢指针到达中点;程序还要考虑链表结点个数的奇偶数因素,当快指针移动x次后到达表尾(1+2x),说明链表有奇数个结点,直接返回慢指针指向的数据即可;如果快指针是倒数第二个结点,说明链表结点个数是偶数,这时可以根据“规则”返回上中位数或下中位数或(上中位数+下中位数)的一半

int GetMedian(List *head){ List *fast = *slow = head; while(fast && slow){ if(fast==NULL){ return slow->data; }else if(fast->next == NULL){ return (double)(slow->data+slow->data)/2; }else{ fast = fast->next->next; slow = slow->next; } }}

emmm……其实还是很简单的

判断循环链表的循环入口位置

快慢指针如果相遇则一定是在环内,可以从这个节点出发,一边继续向前移动一边计数,当再次回到这个节点时,即可得到环中的节点数了

Node* MeetingNode(List *head){ if(head == NULL){ return NULL; } Node *slow = head->next; if(slow == NULL){ return NULL; } Node *fast = slow->next; while(fast && slow){ if(fast == slow){ return fast; } slow = slow->mext; if(fast = fast->next){ fast = fast->next; } } return NULL;} Node* EntryNode(Node *head){ Node *md = MeetingNode(head); if(md == NULL){ return NULL; } int cnt = 1; Node *p = md; while(p!=md){ p = p->next; cnt++; } Node *p = head; for(int i=0; i<cnt; i++){ p = p->next; } Node *q = head; while(q != p){ p = p->next; q = q->next; } return p;}

呵呵,与其说这是一道算法题,不如说像一道初中物理竞赛题(运动部分)

最后,用一张帮助理解的图来结束——

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。