剑指offer--两个链表的第一个公共结点
/** * 输入两个链表,找出它们的第一个公共结点 */ package javabasic.nowcoder; import java.util.HashMap; import java.util.Map; public class Main40 { /*分析:两个单链表如果存在第一个公共结点,则后续结点一定都公共, 因为结点里包含next指针,如果第一个公共结点相同,则next必然相同, 所以第一个公共结点后链表合并。 思路1:设表1长度n,表2长度m,暴力法嵌套遍历两个链表需要O(mn)的时间复杂度, 可以采用hash的思想将其中一个转存为哈希表结构,这样建哈希表时间O(m), 而遍历链表时间O(n),而遍历时查找哈希表的时间为O(1),因此复杂度降为O(m+n), 但需要辅助空间。(这种哈希优化的策略是种一般性的思路,谨记!) */ public ListNode FindFirstCommonNodeI(ListNode pHead1, ListNode pHead2) { if(pHead1==null||pHead2==null)return null; ListNode p = pHead1; ListNode q = pHead2; Map<ListNode,Integer> record = new HashMap<ListNode,Integer>(); while(p!=null) { record.put(p, null); p=p.next; } while(q!=null) { if(record.containsKey(q)) { return q; } q = q.next; } return null; } /* 思路2:开始遍历两遍链表获取两个表的长度,比较长度让长的一个先走差值个步长, 再两个一起走。(快慢指针思想,也是链表问题的一般性思路) */ public ListNode FindFirstCommonNodeII(ListNode pHead1, ListNode pHead2) { if(pHead1==null||pHead2==null)return null; ListNode p = pHead1; ListNode q = pHead2; int length1 = getLength(p); int length2 = getLength(q); //如果链表1的长度大于链表2的长度 if(length1>=length2) { int len = length1-length2; //先遍历链表1,遍历的长度就是两链表的长度差 while(len>0) { p=p.next; len--; } }else if(length1<length2) { //如果链表2的长度大于链表1的长度 int len = length2-length1; //先遍历链表2,遍历的长度就是两链表的长度差 while(len>0) { q=q.next; len--; } } //开始齐头并进,直到找到第一个公共结点 while(p!=q) { p=p.next; q=q.next; } return p; } //求指定链表的长度 private int getLength(ListNode q) { int length = 0; ListNode current = q; while(current!=null) { length++; current=current.next; } return length; } /** * 思路:如果有公共节点,1)若两个链表长度相等,那么遍历一遍后,在某个时刻,p1 == p2 * 2)若两个链表长度不相等,那么短的那个链表的指针pn(也就是p1或p2) * 必先为null,那么这时再另pn = 链表头节点。经过一段时间后, * 则一定会出现p1 == p2。 * 如果没有公共节点:这种情况可以看成是公共节点为null,顾不用再考虑。 */ public ListNode FindFirstCommonNodeIII(ListNode pHead1, ListNode pHead2) { if(pHead1==null||pHead2==null)return null; ListNode p = pHead1; ListNode q = pHead2; while(p!=q) { if(p!=null) { p=p.next; } if(q!=null) { q=q.next; } if(p!=q) { if(p==null) { p=pHead1; } if(q==null) { q=pHead2; } } } return p; } }