最近看到关于环的算法题以为颇有意思,因而思考了一会,如今分几步把解法展现出来.java
问题1:如何检测一个单链表有环.算法
设两个指针,p=head,q=head,从头结点开始,每次p = p.next , q= q.next.next ,若是能找到一点p==q就说明这个有环.
this
问题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} 最终找到圆环的起点.code
附上代码:get
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:两个无环单链表有一个结点相交,找出这个交点.class
最烂的解法:变量
循环H1的结点,H1的每一个结点与H2的全部结点对比,时间复杂度是O(n*m)循环
最简单的解法:遍历
找到H1的长度m,找到H2的长度n.较长的结点先移动m-n的长度,而后遍历循环两个链表,结束的条件是p.next=q.next 时间复杂度是O().
最方便的解法:
把H1链表结点依次放到HashSet中,而后再把H2链表结点依次放入HashSet中,直到没法放入的时候就找到这个相交的节点了.
最优雅的解法:
把H1最后的结点指向H1的头部.而后就把问题转换成问题2了.