算法小知识------10.16----关于链表的相关算法(2)

1,167 阅读2分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

如果链表有环,求出环的长度

求出环的长度,可以在之前判断是否有环的基础上,做出修改

  • 首先,在确定有环的前提下,求出环的长度

    • 在首次两指针相等的节点开始,再次出发,直到再次回到该节点的时候,就证明已经完成一圈了
    • 也可以用双指针的方法去实现,双指针在相等节点同时出发,A节点速度比B节点快,当两节点再次相遇时,A节点追上B节点并且超出了相应的距离。A和B的速度差决定了A比B多走了几圈

实现

  • 基于空间复杂度的考虑,采用第一种方法,并且结合之前的判断有环方法
/**
* 判断是否有环并且输出环的长度
*
* @param head 链表头节点 
*/
    public static Integer isCycle(ListNode head){
        ListNode p1 = head;
        ListNode p2 = head;
        while(p2 != null && p2.next != null){
            p1 = p1.next;
            p2 = p2.next.next;
            if(p1 == p2){
                return getCycleLength(p1);
            }
        }
        return 0;
    }
​
/**
* 求出链表的环长度
*
* @param head 链表 
*/
    public static Integer getCycleLength(ListNode head){
        if(head == null){
            return 0;
        }
        ListNode p1 = head;
        Integer length = 0;
        while(p1 != null){
            p1 = p1.next;
            length++;
            if(p1 == head){
                return length;
            }
        }
        return 0;
    }

如果链表有环,求出 入环的节点

  • 在上述实现了判断链表是否有环,求出环的长度,延伸拓展入环的节点

  • 首先,头结点到入环节点的距离为D

  • 入环节点到首次相遇为S1,首次相遇到入环节点为S2

  • 节点A到第一次相遇的距离为:D+S1;节点B到第一次相遇的距离为:D+S1+n(S1+S2);n为速度差

  • 因为节点B的速度是节点A的2倍,所以:2(D+S1) = D+S1+n(S1+S2) ;

  • 整理得: D = (n-1)(S1+S2)+S2;也就是说从链表头结点到入环点的距离,等于从首次相遇点绕环

    n-1圈再回到入环点的距离。

  • 所以只需要一个指针放在头节点,一个指针放在首次相遇节点,再次相遇时,则为入环节点

实现

/**
* 输出环的入环节点
*
* @param head 链表头节点 
*/
    public static Integer isCycle(ListNode head){
        ListNode p1 = head;
        ListNode p2 = head;
        while(p2 != null && p2.next != null){
            p1 = p1.next;
            p2 = p2.next.next;
            while(p1 == p2){
               p1 = head;
                while(p1 != p2){
                    p1 = p1.next;
                    p2 = p2.next;
                }
                return p1.val;
                
            }
        }
        return 0;
    }