当前位置:  首页>> 技术小册>> 数据结构与算法(下)

题目描述

给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null

解法

  • 先利用快慢指针。若能相遇,说明存在环,且相遇点一定是在环上;若没有相遇,说明不存在环,返回 null
  • 固定当前相遇点,用一个指针继续走,同时累积结点数。计算出环的结点个数 cnt
  • 指针 p1 先走 cnt 步,p2 指向链表头部,之后 p1,p2 同时走,相遇时,相遇点一定是在环的入口处。因为 p1p2 多走了环的一圈。
  1. /**
  2. * @author bingo
  3. * @since 2018/11/22
  4. */
  5. /*
  6. public class ListNode {
  7. int val;
  8. ListNode next = null;
  9. ListNode(int val) {
  10. this.val = val;
  11. }
  12. }
  13. */
  14. public class Solution {
  15. /**
  16. * 求链表环的入口,若没有环,返回null
  17. * @param pHead 链表头
  18. * @return 环的入口点
  19. */
  20. public ListNode EntryNodeOfLoop(ListNode pHead) {
  21. if (pHead == null || pHead.next == null) {
  22. return null;
  23. }
  24. ListNode fast = pHead;
  25. ListNode slow = pHead;
  26. boolean flag = false;
  27. while (fast != null && fast.next != null) {
  28. slow = slow.next;
  29. fast = fast.next.next;
  30. if (fast == slow) {
  31. flag = true;
  32. break;
  33. }
  34. }
  35. // 快指针与慢指针没有相遇,说明无环,返回 null
  36. if (!flag) {
  37. return null;
  38. }
  39. ListNode cur = slow.next;
  40. // 求出环中结点个数
  41. int cnt = 1;
  42. while (cur != slow) {
  43. cur = cur.next;
  44. ++cnt;
  45. }
  46. // 指针p1先走cnt步
  47. ListNode p1 = pHead;
  48. for (int i = 0; i < cnt; ++i) {
  49. p1 = p1.next;
  50. }
  51. // p2指向链表头,然后p1/p2同时走,首次相遇的地方就是环的入口
  52. ListNode p2 = pHead;
  53. while (p1 != p2) {
  54. p1 = p1.next;
  55. p2 = p2.next;
  56. }
  57. return p1;
  58. }
  59. }

测试用例

  1. 功能测试(链表中包含/不包含环;链表中有多个或者只有一个节点);
  2. 特殊输入测试(链表头节点为空指针)。

该分类下的相关小册推荐: