您的位置:首页 > Web前端

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

2015-12-13 20:02 459 查看
T:

题目描述

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

基本做法

不考虑其中潜在的规律,就按照一般的方法,创建一个list,把扫描过的节点都存储在list中,知道下一个节点在list中已经存在,那就说明该节点就是入口节点。

这种方式下的时间复杂度为O(n2)O(n^2)

我的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;
}
}


规律求解

首先是设置两个指针p1,p2p_1, p_2,一个指针p1p_1步长为1,p2p_2步长为2,让两个指针都从头结点往后走,如果存在环的话,两者肯定会再次相遇,因为在两个指针都进入环的时候,一个步长为2,一个步长为1,那就是说两个指针之间的距离每走一步就缩小1个单位,所以两个指针肯定会再次相遇。

在相遇的时候,假设指针p1p_1走了xx步,那么p2p_2肯定走了2x2x步,因为每次p2p2都比p1p_1多走了一步。

同时,还会发现,这个p2p_2多走的xx步,肯定是多走在了换上,也就是说,xx是环的长度nn的整数倍,即有如下公式:

2x=x+k∗nk=1,2,3,…2x = x + k*n \qquad k = 1,2,3,\dots

p2p_2至少围着环转了一圈。



也就说,让一个指针指向环上的相遇点,一个指针指向头结点,同时以步长为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;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: