出题:判断一个单向链表是否有环,如果有环则找到环入口节点;
分析:
- 第一个问题:使用快慢指针(fast指针一次走两步,slow指针一次走一步,并判断是否到达NULL,如果fast==slow成立,则说明链表有环);
- 第二个问题:fast与slow相遇时,slow一定还没有走完一圈(反证法可证明);
示意图
A为起始点,B为环入口点,C为相遇点,则a1=|AB|表示起始点到换入口的距离,a2=|CB|表示相遇点到环入口点的距离,s1=|AB|+|BC|表示slow指针走的长度,s2表示fast指针走的长度,C=|BCB|表示环的长度
由于fast的速度是slow的2倍,所以相遇的时候走过的长度也是2倍
s2=2*s1=a1+N*C+(s1-a1) (1)
N表示fast在环中走的圈数,化解(1)得到:
s1=N*C (2)
找到a1和a2的关系:
a2=C-(s1-a1) (3)
将(2)代入(3)得到:
a1=a2+(N-1)*C (4)
所以如果指针m从起始点A出发,指针n从相遇点C出发,n绕行(N-1)圈环之后最终跟m指针在B点相遇
解题:
1 struct Node { 2 int v; 3 Node *next; 4 }; 5 Node* IsCycle(Node *head) { 6 Node *fast=head, *slow=head; 7 8 while(true) { 9 if(fast!=NULL) 10 fast=fast->next; 11 if(fast!=NULL) 12 fast=fast->next; 13 else 14 return NULL; 15 if(slow!=NULL) 16 slow=slow->next; 17 else 18 return NULL; 19 20 if(fast==slow) 21 return fast; 22 } 23 } 24 Node* FindEntry(Node *head, Node *joint) { 25 Node *m=head, *n=joint; 26 while(true) { 27 if(m==n) 28 return m; 29 m=m->next; 30 n=n->next; 31 } 32 } 33 int main() { 34 Node* b1=new Node(); b1->v=1; 35 Node* b2=new Node(); b2->v=2;b1->next=b2; 36 Node* b3=new Node(); b3->v=3;b2->next=b3; 37 Node* b4=new Node(); b4->v=4;b3->next=b4; 38 Node* b5=new Node(); b5->v=5;b4->next=b5; 39 Node* b6=new Node(); b6->v=6;b5->next=b6; 40 Node* b7=new Node(); b7->v=7;b6->next=b7; 41 Node* b8=new Node(); b8->v=8;b7->next=b8; b8->next=b3; 42 43 Node* temp; 44 if((temp=IsCycle(b1))!=NULL) { 45 printf(" the joint point is: %d",temp->v); 46 printf(" the entry of cycle is: %d",FindEntry(b1,temp)->v); 47 } 48 else 49 printf(" there is no cycle."); 50 return 0; 51 }
出题:判断两棵二元树是否相等(左右子树不能交叉比较);
分析:使用递归实现,在树的K层,有2^K 个节点,所以会进行(2^K)*2次调用,所以时间复杂度为O(N);
解题:
1 struct Node { 2 int value; 3 Node *left; 4 Node *right; 5 }; 6 7 bool CompareTree(Node *first, Node *second) { 8 if(first==NULL && second==NULL) 9 return true; 10 if((first==NULL && second!=NULL) || 11 (first!=NULL && second==NULL)) 12 return false; 13 if(first->value!=second->value) 14 return false; 15 return CompareTree(first->left,second->left) && 16 CompareTree(first->right, second->right); 17 }