剑指offer——链表中环的入口结点

剑指offer——链表中环的入口结点

1 题目描述

一个链表中包含环,请找出该链表的环的入口结点。

2 我的思路:直接利用链表结构解决问题

直接利用链表,过程如下:

  1. 定义链表结构,增设一个flag,初始flag为false;
  2. 然后遍历链表,每访问一个结点,将flag赋值为true;
  3. 访问下一个结点时,判断其flag值,若为true,则为第二次访问该结点,则该结点必定为环的入口结点。

代码如下:

class ListNode {
    int val;
    boolean flag=false;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}
public class Solution {
    public ListNode EntryNodeOfLoop(ListNode pHead)
    {
        ListNode p=pHead;
        while(p!=null){
            if(p.flag==true){
                break;
            }
            p.flag=true;
            p=p.next;
        }
        return p;//思考,该return不能放在while中是为什么?
    }
}

思考解答:你的代码里确保有东西返回。编译器认为if判断不一定会有东西返回。for中也是有判断,while中也有。return用在这些的时候,在循环体外面需要return。

编译器认为while语句有在任何情况下都能执行的能力,但是只在入参为true的情况下有该能力。JVM不知道当istrue为假的时候该怎么办,所以报错.


public int locate(){
        while (isTrue())
            return 4;
    }
 boolean isTrue(){
    return true;
  }

这段代码却会报错, 这是因为编译器认为while语句有在任何情况下都能执行的能力,但是只在入参为true的情况下有该能力。JVM不知道当istrue为假的时候该怎么办,所以报错.

public int locate(){
    while (isTrue())
        return 4;
    return 0;
}
boolean isTrue(){
    return true;
}

这段代码也不会报错,因为添加了return 0;虽然说JVM不知道当istrue为假的时候该怎么办,但是仍然会返回0值,方法就有了返回值.

因此上述代码可做一点改动:

class ListNode {
    int val;
    boolean flag=false;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}
public class Solution {
    public ListNode EntryNodeOfLoop(ListNode pHead)
    {
        ListNode p=pHead;
        while(p!=null){
            if(p.flag==true){
                return p;
            }
            p.flag=true;
            p=p.next;
        }
        return null;//告诉编译器,当while循环语句不能执行时,仍然有可以返回的值。
    }
}

参考学习资料:Java知识点——return语句,结束语句

3 利用数学公式找规律解决

第一步,找环中相汇点。分别用p1,p2指向链表头部,p1每次走一步,p2每次走二步,直到p1==p2找到在环中的相汇点。
第二步,找环的入口。接上步,当p1==p2时,p2所经过节点数为2x,p1所经过节点数为x,设环中有n个节点,p2比p1多走一圈有2x=n+x; n=x;可以看出p1实际走了一个环的步数。
第三步,设入口顺时针走到p2的距离为a,则p2顺时针走到出口(即入口)的距离为n-a。链表长度为x+n-a,链表头结点到入口距离为x+n-a-n=x-a。又因为x=n,则链表头结点到入口距离为n-a,等于p2顺时针走到出口(即入口)的距离。因此让p2指向链表头部,p1位置不变,p1,p2每次走一步直到p1==p2; 此时p1指向环的入口。

源码如下:

/*
 public class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}
*/
public class Solution {

    public ListNode EntryNodeOfLoop(ListNode pHead)
    {
        if(pHead==null || pHead.next==null){
            return null;
        }
        ListNode p1=pHead;
        ListNode p2=pHead;
        while(p1!=null && p2.next!=null){
            p1=p1.next;
            p2=p2.next.next;
            if(p1==p2){
                p1=pHead;
                while(p1!=p2){
                    p1=p1.next;
                    p2=p2.next;
                }
                return p1;
            }
        }
        return null;
    }
}

猜你喜欢

转载自blog.csdn.net/yangxingpa/article/details/80752281