您的位置:首页 > 理论基础 > 数据结构算法

一道算法题目的思考

2015-04-10 00:00 330 查看
摘要: 最近看到关于环的算法题觉得很有意思,于是思考了一会,现在分几步把解法展示出来.

问题1:如何检测一个单链表有环.
问题2:一个有环的单链表找出环的入口.
问题3:两个无环单链表有一个结点相交,找出这个交点.

最近看到关于环的算法题觉得很有意思,于是思考了一会,现在分几步把解法展示出来.

问题1:如何检测一个单链表有环.



设两个指针,p=head,q=head,从头结点开始,每次p = p.next , q= q.next.next ,如果能找到一点p==q就说明这个有环.

问题2:一个有环的单链表找出环的入口.



如图所示,设置3个变量,根据第一次相遇时,q走的距离是p的两倍,可以列出一个方程等式, 2*(a+b) =a+2b+c,最后可以简化成 a = c.那么从第一次相遇的焦点到圆环的起始点和从head到圆环的起始点实际上结点数一样多,这样就可可以通过循环判断来完成.p=head , q=第一次相遇点. while(p!= q) {p=p.next ; q=q.next} 最终找到圆环的起点.

附上代码:

public class FindFrstCircleNode {
public static void main(String[] args) {
Node<Integer> head = new Node<Integer>(1);
Node<Integer> n1 = new Node<Integer>(2);
Node<Integer> n2 = new Node<Integer>(3);
Node<Integer> n3 = new Node<Integer>(4);
Node<Integer> n4 = new Node<Integer>(5);
Node<Integer> n5 = new Node<Integer>(6);
Node<Integer> n6 = new Node<Integer>(7);
Node<Integer> n7 = new Node<Integer>(8);
Node<Integer> n8 = new Node<Integer>(9);
Node<Integer> n9 = new Node<Integer>(10);

head.next = n1;
n1.next = n2;
n2.next = n3;
n3.next = n4;
n4.next = n5;
n5.next = n6;
n6.next = n7;
n7.next = n8;
n8.next = n9;
n9.next = n5;

FindFrstCircleNode ffcn = new FindFrstCircleNode();
Node<Integer> p = ffcn.getFirstCircleNode(head);
System.out.println(p.data);

}

public Node<Integer> getFirstCircleNode(Node<Integer> head) {
Node<Integer> p = head;
Node<Integer> q = head;
int count = 0;
while (count == 0 || p != q) {
p = p.next;
q = q.next.next;
count++;
}
p = head;

while (p != q) {
p = p.next;
q = q.next;
}
return p;

}

static class Node<T> {
T data;
Node<T> next;

public Node() {
super();
}
public Node(T data) {
super();
this.data = data;
}
}
}

问题3:两个无环单链表有一个结点相交,找出这个交点.



最烂的解法:

循环H1的结点,H1的每个结点与H2的所有结点对比,时间复杂度是O(n*m)

最简单的解法:

找到H1的长度m,找到H2的长度n.较长的结点先移动m-n的长度,然后遍历循环两个链表,结束的条件是p.next=q.next 时间复杂度是O().

最方便的解法:

把H1链表结点依次放到HashSet中,然后再把H2链表结点依次放入HashSet中,直到无法放入的时候就找到这个相交的节点了.

最优雅的解法:

把H1最后的结点指向H1的头部.然后就把问题转换成问题2了.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息