链表---判断一个链表是否有环以及找到环开始的节点

如果队列中含有圆环,那么对队列的遍历会有什么影响呢。试想有一个圆形跑道,甲乙两人同时在跑道的起点,如果甲的速度是乙的两倍,那么当乙跑完半圈时,甲跑完一圈回到起点,乙跑完一圈回到起点时,甲跑完两圈也回到起点,这样的话,甲乙重新在起点相遇。

采用上面的思路,如果我们使用两个指针分别从队列的起点出发,一个指针前进一次遍历1个节点,另一个指针前进一次,遍历2个节点,如果队列中有环,那么我们可以确信,前进若干次之后,两个指针会相遇,于是算法就是让两个指针同时前进,如果两个指针能相遇的话,那么可以断定链表中有环

//1 思路:二指针,一个一次走一步,一个一次走两步。出现相遇点则有环
    public boolean hasCycle1(ListNode head) {
     if (head == null || head.next == null) return false;
     ListNode slow = head;
        ListNode fast = head;
        while(fast != null && fast.next != null) {
             slow = slow.next;
             fast = fast.next.next;
             if(slow == fast) return true;
        }
        return false;
    }

找到环开始的节点

/**
 *
思路1、假设x为从头结点到环开始的节点的距离,k为从环开始节点到相遇节点的距离,y为环的长度。
两个指针slow fast,slow每次走一步,fast每次走两步,则有
t = X + nY + K
2t = X + mY + K
化简可以得到:
X+K  =  (m-2n)Y   即 (k=y-x)
或者X = (Y - K) + (m - 2n - 1)Y
则可以得到 :从相遇节点往下走到环的开始节点的距离和从head节点到环的开始节点的距离相等。
 */
     //1
     public ListNode detectCycle(ListNode head) {
          ListNode fast=head;
          ListNode slow=head;
          while(fast!=null&&fast.next!=null){
              slow=slow.next;
              fast=fast.next.next;
              if(fast==slow){
                   break;
              }
          }
          if(fast==null||fast.next==null){
              return null;
          }
          //走到这里说明有环
          slow=head;
          while(slow!=fast){
              slow=slow.next;
              fast=fast.next;
          }
     return slow;
    }

猜你喜欢

转载自blog.csdn.net/l1394049664/article/details/81369374
今日推荐