输入一个单向链表,输出该链表中倒数第k个结点,
链表的倒数第0个结点为链表的尾指针。
相信,稍微有点 经验的同志,都会说到:设置两个指针p1,p2,首先p1和p2都指向head,然后p2向前走k步,这样p1和p2之间就间隔k个节点,最后p1和p2同时向前移动,直至p2走到链表末尾。
struct ListNode
|
这是针对链表单项链表查找其中倒数第k个结点。试问,如果链表是双向的,且可能存在环呢?编程判断两个链表是否相交。
给出两个单向链表的头指针(如下图所示),
比如h1、h2,判断这两个链表是否相交。这里为了简化问题,我们假设两个链表均不带环。
编程之美的解析:
- 直接循环判断第一个链表的每个节点是否在第二个链表中。但,这种方法的时间复杂度为O(Length(h1) * Length(h2))。显然,我们得找到一种更为有效的方法,至少不能是O(N^2)的复杂度。
- 针对第一个链表直接构造hash表,然后查询hash表,判断第二个链表的每个结点是否在hash表出现,如果所有的第二个链表的结点都能在hash表中找到,即说明第二个链表与第一个链表有相同的结点。时间复杂度为为线性:O(Length(h1) + Length(h2)),同时为了存储第一个链表的所有节点,空间复杂度为O(Length(h1))。是否还有更好的方法呢,既能够以线性时间复杂度解决问题,又能减少存储空间?
- 进一步考虑“如果两个没有环的链表相交于某一节点,那么在这个节点之后的所有节点都是两个链表共有的”这个特点,我们可以知道,如果它们相交,则最后一个节点一定是共有的。而我们很容易能得到链表的最后一个节点,所以这成了我们简化解法的一个主要突破口。那么,我们只要判断俩个链表的尾指针是否相等。相等,则链表相交;否则,链表不相交,O((Length(h1) + Length(h2))
- 上面的问题都是针对链表无环的,那么如果现在,链表是有环的呢?还能找到最后一个结点进行判断么?上面的方法还同样有效么?显然,这个问题的本质已经转化为判断链表是否有环。那么,如何来判断链表是否有环呢?
所以,事实上,这个判断两个链表是否相交的问题就转化成了:
1.先判断带不带环
2.如果都不带环,就判断尾节点是否相等
3.如果都带环,判断一链表上俩指针相遇的那个节点,在不在另一条链表上。
如果在,则相交,如果不在,则不相交。
如何编写代码来判断链表是否有环呢?因为很多的时候,你给出了问题的思路后,面试官可能还要追加你的代码,ok,如下(设置两个指针(p1, p2),初始值都指向头,p1每次前进一步,p2每次前进二步,如果链表存在环,则p2先进入环,p1后进入环,两个指针在环中走动,必定相遇):
1. //copyright@ KurtWang 2. //July、2011.05.27。 3. struct Node 4. { 5. int value; 6. Node * next; 7. }; 8. 9. //1.先判断带不带环 10. //判断是否有环,返回bool,如果有环,返回环里的节点 11. //思路:用两个指针,一个指针步长为1,一个指针步长为2,判断链表是否有环 12. bool isCircle(Node * head, Node *& circleNode, Node *& lastNode) 13. { 14. Node * fast = head->next; 15. Node * slow = head; 16. while(fast != slow && fast && slow) 17. { 18. if(fast->next != NULL) 19. fast = fast->next; 20. 21. if(fast->next == NULL) 22. lastNode = fast; 23. if(slow->next == NULL) 24. lastNode = slow; 25. 26. fast = fast->next; 27. slow = slow->next; 28. 29. } 30. if(fast == slow && fast && slow) 31. { 32. circleNode = fast; 33. return true; 34. } 35. else 36. return false; 37. } |
如果都不带环,就判断尾节点是否相等,如果都带环,判断一链表上俩指针相遇的那个节点,在不在另一条链表上。下面是综合解决这个问题的代码:
1. //判断带环不带环时链表是否相交 2. //2.如果都不带环,就判断尾节点是否相等 3. //3.如果都带环,判断一链表上俩指针相遇的那个节点,在不在另一条链表上。 4. bool detect(Node * head1, Node * head2) 5. { 6. Node * circleNode1; 7. Node * circleNode2; 8. Node * lastNode1; 9. Node * lastNode2; 10. 11. bool isCircle1 = isCircle(head1,circleNode1, lastNode1); 12. bool isCircle2 = isCircle(head2,circleNode2, lastNode2); 13. 14. //一个有环,一个无环 15. if(isCircle1 != isCircle2) 16. return false; 17. //两个都无环,判断最后一个节点是否相等 18. else if(!isCircle1 && !isCircle2) 19. { 20. return lastNode1 == lastNode2; 21. } 22. //两个都有环,判断环里的节点是否能到达另一个链表环里的节点 23. else 24. { 25. Node * temp = circleNode1->next; //updated,多谢苍狼 and hyy。 26. while(temp != circleNode1) 27. { 28. if(temp == circleNode2) 29. return true; 30. temp = temp->next; 31. } 32. return false; 33. } 34. 35. return false; 36. } |