剑指offer——链表中环的入口结点
1 题目描述
一个链表中包含环,请找出该链表的环的入口结点。
2 我的思路:直接利用链表结构解决问题
直接利用链表,过程如下:
- 定义链表结构,增设一个flag,初始flag为false;
- 然后遍历链表,每访问一个结点,将flag赋值为true;
- 访问下一个结点时,判断其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;
}
}