您的位置:首页 > 职场人生

判断链表环相关的面试题

2017-05-23 17:05 211 查看
题目1:判断链表是否有环

       首先应判断两个单链表是否含有环,判断是否有环的方法很多,目前最好的方法是:一开始设置两个指针都指向表头,其中一个每次(一步)前进一个节点的叫p1,另外那个每次(一步)前进两个节点的叫p2 。p1和p2同时走,当其中有一个遇到null,就证明链表没有环。如何某个时刻(假设走了n步之后),p1和p2指向的地址相同,那么链表就是有环的。

//判断链表是否有环
public boolean hasLoop(Node head) {
Node first = head;
Node second = head;
//判断条件second在前,second.next在后,否则可能会报空指针异常
while(second != null && second.next != null ) {
first = first.next;
second = second.next.next;
if(first == second)
return true;
}
return false;
}

题目2:如果链表有环,求环的长度:

       若链表无环,则其长度为0;若链表有环,则second和first指针相遇时,相遇点一定在环中。记录下相遇点,first再次走到该点时走到长度即为所求。

//首先得到相遇点
private Node getMeetNode(Node head) {
Node first = head;
Node second = head;
//判断条件second在前,second.next在后,否则可能会报空指针异常
while(second != null && second.next != null  ) {
first = first.next;
second = second.next.next;
if(first == second)
return first;
}
return null;
}

public int getLoopLength(Node head) {

Node meetNode = getMeetNode(head);//获取相遇点的指针
if(meetNode == null) //无环
return 0;
Node first = meetNode.next;
int result = 1;
while(first != meetNode) {
result++;
first = first.next;
}
return result;
}

题目3:链表环的入口点:

       根据结论:从两个指针相遇点 和 两个指针头结点 这两个位置出发,走相同的步长,他们的相遇点就是环的入口点。具体推导过程见这里点击打开链接。

       定义两个指针first、second,让first先走 len 步,然后first和second一起向前走,两者必然会相遇,相遇点即为环的入口结点。

public Node entryNodeOfLoop(Node head){

Node first = head;
Node second = head;
int len = getLoopLength(head);
if(len == 0)
return null;
for(int i=0; i<len; i++) {
first = first.next;
}
while(first != null) {
if(first == second) {
return first;
}
first = first.next;
second = second.next;
}
return null;
}

题目4:判断两个链表是否相交

       两个链表相交有以下三种情况:1.两链表均不含环 2.两链表均含环 3.一个有环一个无环,显然两链表此时不可能相交,该情况不考虑。

       1.均无环的情况下判断是否相交,且找出第一个相交点。无环情况下,判断是否相交,可以让两个链表均遍历至尾节点,如果尾节点相同,则说明两链表是有交点的,代码如下:

/*
* 无环情况下判断是否相交 两个链表无环时若相交,则至少尾节点必然是同一个
*/
public boolean isJointNoLoop(Node h1, Node h2) {
Node p = h1;
Node q = h2;
while (p.next != null) {
p = p.next;
}
while (q.next != null) {
q = q.next;
}
return p == q;
}        此时已判断出是否相交,相交后,来寻找第一个相交点,算出两个链表的长度差δ,两个指针从表头出发,之后较长的链表先移动δ步,之后两链表同时移动,直到遇到相同的节点,该节点即为第一个相交点,代码如下:

/*
* 无环情况下找出第一个相交点
*/
public Node getFirstJoint(Node h1, Node h2) {
int len1 = 0;
int len2 = 0;
while (h1.next != null) {
len1++;
h1 = h1.next;
}
while (h2.next != null) {
len2++;
h2 = h2.next;
}
return len1-len2>=0?getNode(h1,h2,len1,len2):getNode(h2, h1, len2, len1);
}

private Node getNode(Node h1, Node h2, int len1, int len2) {
int i = 0;
while (i < len1 - len2) {
h1 = h1.next;
}
while (true) {
h1 = h1.next;
h2 = h2.next;
if (h1 == h2)
return h1;
}
}

       2.均有环的情况下,判断是否相交

       思路与无环时的思路较类似,二者均有环,那么可以找出各自环的入口点,然后从各自的入口点出发,一个快速(每次2步),一个慢速(每次1步),直到相遇,说明相交。

相关参考博客:

http://blog.csdn.net/yx0628/article/details/24454693

http://wuchong.me/blog/2014/03/25/interview-link-questions/

http://www.jianshu.com/p/c65d9d753c31

http://www.cnblogs.com/smyhvae/p/4782595.html


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐