更多2019年的技术文章,欢迎关注我的微信公众号:码不停蹄的小鼠松(微信号:busy_squirrel),也可扫下方二维码关注获取最新文章哦~
T:
题目描述
一个链表中包含环,请找出该链表的环的入口结点。
基本做法
不考虑其中潜在的规律,就按照一般的方法,创建一个list,把扫描过的节点都存储在list中,知道下一个节点在list中已经存在,那就说明该节点就是入口节点。
这种方式下的时间复杂度为 O ( n 2 ) O(n^2) O(n2)
我的code:
/*
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}
*/
import java.util.ArrayList;
import java.util.List;
/**
* T: 链表中环的入口结点
*
* 题目描述
* 一个链表中包含环,请找出该链表的环的入口结点。
*
* date: 2015.12.13 19:28
* @author SSS
*
*/
public class Solution {
/**
* 将所有扫描过的节点都放在list列表中,
* 看是否下一个节点已经在list列表中出现过
* @param pHead
* @return
*/
public ListNode EntryNodeOfLoop(ListNode pHead){
ListNode targetNode = new ListNode(3);
if (pHead == null || pHead.next == null) {
return null;
}
List<ListNode> nodesList = new ArrayList<ListNode>();
nodesList.add(pHead);
targetNode = pHead.next;
while (!nodesList.contains(targetNode)) {
nodesList.add(targetNode);
targetNode = targetNode.next;
}
return targetNode;
}
}
规律求解
首先是设置两个指针 p 1 , p 2 p_1, p_2 p1,p2,一个指针 p 1 p_1 p1步长为1, p 2 p_2 p2步长为2,让两个指针都从头结点往后走,如果存在环的话,两者肯定会再次相遇,因为在两个指针都进入环的时候,一个步长为2,一个步长为1,那就是说两个指针之间的距离每走一步就缩小1个单位,所以两个指针肯定会再次相遇。
在相遇的时候,假设指针 p 1 p_1 p1走了 x x x步,那么 p 2 p_2 p2肯定走了 2 x 2x 2x步,因为每次 p 2 p2 p2都比 p 1 p_1 p1多走了一步。
同时,还会发现,这个 p 2 p_2 p2多走的 x x x步,肯定是多走在了换上,也就是说, x x x是环的长度 n n n的整数倍,即有如下公式:
2 x = x + k ∗ n k = 1 , 2 , 3 , … 2x = x + k*n \qquad k = 1,2,3,\dots 2x=x+k∗nk=1,2,3,…
p 2 p_2 p2至少围着环转了一圈。
也就说,让一个指针指向环上的相遇点,一个指针指向头结点,同时以步长为1往后走,其碰头的那个结点,就是入口结点。
我的code:
/*
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}
*/
/**
* T: 链表中环的入口结点
*
* 题目描述
* 一个链表中包含环,请找出该链表的环的入口结点。
*
* date: 2015.12.13 19:39
* @author SSS
*
*/
public class Solution {
/**
* 两个指针,一个指针步长为1,一个步长为2;
* 先计算两个指针相交的位置点;
* 然后让一个指针指向头结点,步长都为1,往后走,其相遇点就是入口点
* 该规律可通过公式推导得出
* @param pHead
* @return
*/
public ListNode EntryNodeOfLoop(ListNode pHead){
ListNode targetNode = new ListNode(3);
if (pHead == null || pHead.next == null) {
return null;
}
ListNode preNode = pHead.next;
ListNode postNode = pHead.next.next;
// 找到相遇点
while (preNode != postNode) {
preNode = preNode.next;
postNode = postNode.next.next;
}
// 将其中一个指针指向头结点
postNode = pHead;
// 步长都为1,同时往后走,直到两者相遇
// 相遇点就是入口
while (preNode != postNode) {
preNode = preNode.next;
postNode = postNode.next;
}
targetNode = preNode;
return targetNode;
}
}
更多2019年的技术文章,欢迎关注我的微信公众号:码不停蹄的小鼠松(微信号:busy_squirrel),也可扫下方二维码关注获取最新文章哦~