[剑指Offer]链表中环的入口结点

 

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

法1

能通过,但是复杂度过大,思路为遍历
首先从头节点开始,依次遍历单链表的每一个节点。

每遍历到一个新节点,就从头节点重新遍历新节点之前的所有节点,

用新节点ID和此节点之前所有节点ID依次作比较。

如果发现新节点之前的所有节点当中存在相同节点ID, 则说明该节点被遍历过两次,链表有环;

如果之前的所有节点当中不存在相同的节点,就继续遍历下一个新节点,继续重复刚才的操作。


时间复杂度o(n*n) 空间复杂度o(1)

 public ListNode EntryNodeOfLoop1(ListNode pHead) {
  ListNode cur = pHead;
  ListNode inner = cur;
  int count = 0;//计数,防止cur和inner相撞,
  // 每次移动cur,inner只能遍历cur的前面的元素,其他不允许
  while (cur != null) {
   count++;
   int incount = count;
   while (inner != null) {
    incount--;
    if (incount == 0) break;
    if (inner.val == cur.val) return inner;
    inner = inner.next;
   }
   cur = cur.next;
   inner = pHead;
  }

  return null;
 }

法二

首先创建一个以节点ID为键的HashSet集合, 用来存储曾经遍历过的节点。

然后同样是从头节点开始,依次遍历单链表的每一个节点。

每遍历到一个新节点,就用新节点和HashSet集合当中存储的节点作比较, 如果发现HashSet当中存在相同节点ID,则说明链表有环, 如果HashSet当中不存在相同的节点ID, 就把这个新节点ID存入HashSet,之后进入下一节点,继续重复刚才的操作。

思路:HashSet实现了Set接口,它不允许集合中出现重复元素。

Set添加元素时,如果元素值重复时返回 "false",如果添加成功则返回"true"

时间复杂度o(1) 空间复杂度o(n)

 public ListNode EntryNodeOfLoop2(ListNode pHead) {

  HashSet<Integer> set = new HashSet<>();
  while (pHead != null) {
   if (!set.add(pHead.val)) {//如果add->false->!false->true
    return pHead;
   }
   pHead = pHead.next;
  }
  return null;
 }

法三(最正统的写法)

首先创建两个指针fast和slow,同时指向这个链表的头节点。

然后开始循环,在循环体中,让指针slow每次向下移动一个节点,让指针fast每次向下移动两个节点, 然后比较两个指针指向的节点是否相同。如果不同,则继续下一次循环。

如果相同,则判断出链表有环,

==>fast留在环里,slow重新指向头节点, slow每次往后一次移动一个结点遍历,因为fast留在环里,所以它总会和slow相遇 相遇后就是返回的入口(至于为什么会slow往下走一定能够会和fast相遇却不会错过,这里涉及到数学问题..)

时间复杂度o(n) 空间复杂度o(1)

 public ListNode EntryNodeOfLoop(ListNode pHead) {
  if (pHead == null || pHead.next == null) {
   return null;
  }
  ListNode slow = pHead;
  ListNode fast = pHead;
  while (fast != null && fast.next != null) {
   slow = slow.next;
   fast = fast.next.next;
   if (fast == null) {
    return null;
   }
   if (slow == fast) {
    break;
   }
  }
  slow = pHead;
  while (slow != fast) {
   slow = slow.next;
   fast = fast.next;
  }
  return slow;
 }

测试用例

 public void tests() {// 1 2 3 4 5 3
  ListNode node = new ListNode(1);
  node.next = new ListNode(2);
  node.next.next = new ListNode(3);
  node.next.next.next = new ListNode(4);
  node.next.next.next.next = new ListNode(5);
  node.next.next.next.next.next = node.next.next;//3
  System.out.println(EntryNodeOfLoop1(node).val);
 }

猜你喜欢

转载自blog.csdn.net/qq_38277033/article/details/81223267