链表中环的入口节点
第一步:是如何确定一个链表中包含环(顺便确定环中节点个数)
定义两个指针,同时从链表的头节点出发,一个指针一次走一步,另一个指针一次走两步。
如果走得快的指针追上了走得慢的指针,那么链表就包含环;
如果走的快的指针走到了链表的末尾,都没有追上第一个指针,那么链表就不包含环。
第二步:确定链表环节点的个数;找到环的入口节点
如何得到环中节点的数目
;前面提到判断一个链表里是否有环用到了一快一慢两个指针。如果两个指针相遇,则表明链表中存在环。可以从这个节点出发,以便继续向前移动一边计数,当再次回到这个节点时,就可以得到换种节点数
定义两个指针P1和P2指向链表的节点。
如果链表中的环有n个节点,则指 针P1先在链表上向前移动n步;
两个指针以相同速度向前移动,当第二个指针P2指向环的入口节点时,第一个指针P1已经绕着环走了一圈,又回到了入口节点
package B链表;
/**
* @Author Zhou jian
* @Date 2020 ${month} 2020/1/31 0031 21:53
* 给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null。
*/
public class Problem2 {
public static void main(String[] args) {
ListNode listNode1 = new ListNode(1);
ListNode listNode2 = new ListNode(2);
ListNode listNode3 = new ListNode(3);
ListNode listNode4 = new ListNode(4);
ListNode listNode5 = new ListNode(5);
ListNode listNode6= new ListNode(6);
listNode1.next=listNode2;
listNode2.next=listNode3;
listNode3.next=listNode4;
listNode4.next=listNode5;
listNode5.next=listNode6;
listNode6.next=listNode3;
//判断链表中是否有环
// ListNode meetingNode = Problem2.isLoop(listNode1);
// System.out.println(meetingNode);
System.out.println(Problem2.entryNodeOfLoop(listNode1));
}
//判断链表中是否含有环
/**
* 定义两个指针,同时从链表的头节点出发,一个指针一次走一步,另一个指针一次走两步。
如果走得快的指针追上了走得慢的指针,那么链表就包含环;
如果走的快的指针走到了链表的末尾,都没有追上第一个指针,那么链表就不包含环。
* @param head
* @return 返回相遇的节点
*/
public static ListNode isLoop(ListNode head){
ListNode temp1 = head; //走得快的指针
ListNode temp2 = head; //走的慢的指针
//两个指针不断向前走
while(temp1.next!=null){
if(temp1.next.next!=null){
temp1 = temp1.next.next;
temp2 = temp2.next;
if(temp1==temp2){//走的慢的指针追上了走得快的指针
return temp1;
}
}else{
break;
}
}
return null;
}
/**
* 链表中环的入口节点
* @param phead
* @return
*/
public static ListNode entryNodeOfLoop(ListNode phead){
//环中节点的数量
int countInLoop = 0;
//遍历环求取环中节点的数量
ListNode meetingNode = isLoop(phead);
ListNode temp = meetingNode.next;
countInLoop++;//
while(temp!=meetingNode){
countInLoop++;
temp = temp.next;
}
//从头指针开始
ListNode temp1 = phead;
ListNode temp2 = phead;
//p1指针向前移动countInLoop步
while(countInLoop>0){
temp1 = temp1.next;
countInLoop--;
}
//两个指针以相同速度向前移动,当第二个指针P2指向环的入口节点时
//temp1==temp2时
while(temp1!=temp2){
temp1=temp1.next;
temp2 = temp2.next;
}
return temp1;
}
}
//链表
class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
@Override
public String toString() {
return "ListNode{" +
"val=" + val +
'}';
}
}
把一个问题分解成几个简单的步骤,是一种常用的解决复杂问题的方法。为了解决这个问题,我们可以把它分解成3个步骤:找出环中任意一个节点;得到环中节点数目;找到环的入口节点