判断链表环相关的面试题

题目1:判断链表是否有环

       首先应判断两个单链表是否含有环,判断是否有环的方法很多,目前最好的方法是:一开始设置两个指针都指向表头,其中一个每次(一步)前进一个节点的叫p1,另外那个每次(一步)前进两个节点的叫p2 。p1和p2同时走,当其中有一个遇到null,就证明链表没有环。如何某个时刻(假设走了n步之后),p1和p2指向的地址相同,那么链表就是有环的。

//判断链表是否有环
public boolean hasLoop(Node head) {
    Node first = head;
    Node second = head;
    //判断条件second在前,second.next在后,否则可能会报空指针异常
    while(second != null && second.next != null  ) {
        first = first.next;
        second = second.next.next;
        if(first == second)
            return true;
    }
    return false;
}

题目2:如果链表有环,求环的长度:

       若链表无环,则其长度为0;若链表有环,则second和first指针相遇时,相遇点一定在环中。记录下相遇点,first再次走到该点时走到长度即为所求。

//首先得到相遇点
private Node getMeetNode(Node head) {
    Node first = head;
    Node second = head;
    //判断条件second在前,second.next在后,否则可能会报空指针异常
    while(second != null && second.next != null  ) {
        first = first.next;
        second = second.next.next;
        if(first == second)
            return first;
    }
    return null;
}

public int getLoopLength(Node head) {

    Node meetNode = getMeetNode(head);//获取相遇点的指针
    if(meetNode == null) //无环
        return 0;
    Node first = meetNode.next;
    int result = 1;
    while(first != meetNode) {
        result++;
        first = first.next;
    }
    return result;
}

题目3:链表环的入口点:

       根据结论:从两个指针相遇点 和 两个指针头结点 这两个位置出发,走相同的步长,他们的相遇点就是环的入口点。具体推导过程见这里点击打开链接。

       定义两个指针first、second,让first先走 len 步,然后first和second一起向前走,两者必然会相遇,相遇点即为环的入口结点。

public Node entryNodeOfLoop(Node head){

    Node first = head;
    Node second = head;
    int len = getLoopLength(head);
    if(len == 0)
        return null;
    for(int i=0; i<len; i++) {
        first = first.next;
    }
    while(first != null) {
        if(first == second) {
            return first;
        }
        first = first.next;
        second = second.next;
    }
    return null;
}

题目4:判断两个链表是否相交

       两个链表相交有以下三种情况:1.两链表均不含环 2.两链表均含环 3.一个有环一个无环,显然两链表此时不可能相交,该情况不考虑。

       1.均无环的情况下判断是否相交,且找出第一个相交点。无环情况下,判断是否相交,可以让两个链表均遍历至尾节点,如果尾节点相同,则说明两链表是有交点的,代码如下:

/* 
 * 无环情况下判断是否相交 两个链表无环时若相交,则至少尾节点必然是同一个 
 */  
public boolean isJointNoLoop(Node h1, Node h2) {  
    Node p = h1;  
    Node q = h2;  
    while (p.next != null) {  
        p = p.next;  
    }  
    while (q.next != null) {  
        q = q.next;  
    }  
    return p == q;  
}  
       此时已判断出是否相交,相交后,来寻找第一个相交点,算出两个链表的长度差δ,两个指针从表头出发,之后较长的链表先移动δ步,之后两链表同时移动,直到遇到相同的节点,该节点即为第一个相交点,代码如下:

/* 
 * 无环情况下找出第一个相交点 
 */  
public Node getFirstJoint(Node h1, Node h2) {  
    int len1 = 0;  
    int len2 = 0;  
    while (h1.next != null) {  
        len1++;  
        h1 = h1.next;  
    }  
    while (h2.next != null) {  
        len2++;  
        h2 = h2.next;  
    }  
    return len1-len2>=0?getNode(h1,h2,len1,len2):getNode(h2, h1, len2, len1);  
}  
  
private Node getNode(Node h1, Node h2, int len1, int len2) {  
    int i = 0;  
    while (i < len1 - len2) {  
        h1 = h1.next;  
    }  
    while (true) {  
        h1 = h1.next;  
        h2 = h2.next;  
        if (h1 == h2)  
        return h1;  
    }  
}  

       2.均有环的情况下,判断是否相交

       思路与无环时的思路较类似,二者均有环,那么可以找出各自环的入口点,然后从各自的入口点出发,一个快速(每次2步),一个慢速(每次1步),直到相遇,说明相交。



相关参考博客:

http://blog.csdn.net/yx0628/article/details/24454693

http://wuchong.me/blog/2014/03/25/interview-link-questions/

http://www.jianshu.com/p/c65d9d753c31

http://www.cnblogs.com/smyhvae/p/4782595.html




猜你喜欢

转载自blog.csdn.net/cpcpcp123/article/details/72650359