链表相交问题

问题描述:

给定两链表的头结点,判断两链表是否存在公共部分(相交),若相交返回相交的第一个节点。

经分析发现该问题可以分成如下两个子问题进行解决。

子问题一:两无环链表是否相交

算法一:假设list1长度为L1,list2长度为L2,假设公共部分长为m,由L1 + L2 - m = L2 + L1 -m可知第一路先遍历list1,再遍历list2,第二路先遍历list2再遍历list1,若存在结点在遍历到L1 + L2 - m时两链表值相同,该位置即为相交的第一个节点,若无公共部分,则会使得两个链表全遍历完。

算法一代码实现如下:

     public static Node<Character> selution(Node<Character> head1, Node<Character> head2){
         Node<Character> pointer1 = head1;
         Node<Character> pointer2 = head2;
         boolean flag1 = true, flag2 = true;
         while (pointer1 != pointer2) {
             if(flag1 && pointer1.next == null) {
                 pointer1 = head2;
                 flag1 = false;
             }else {
                 pointer1 = pointer1.next;
             }
             if(flag2 && pointer2.next == null) {
                 pointer2 = head1;
                 flag2 = false;
             }else {
                 pointer2 = pointer2.next;
             }
         }
         return pointer1;
     }

算法二:先遍历两链表获得两链表的长度,叫L1,L2(不妨令L1>L2),先让指向list1的指针向前移动L1-L2的位置,然后两指针一起移动,若存在公共节点则一定会出现两指针指向同一个节点的情况,此时该节点即为所求。

算法二代码如下:

    public static Node<Character> selution1(Node<Character> head1, Node<Character> head2){
         int length1 = 0, length2 = 0;
         for (Node<Character> p = head1; p != null; p = p.next, length1++) {};
         for (Node<Character> p = head2; p != null; p = p.next, length2++) {};
         Node<Character> pLong, pShort;
         int diff = Math.abs(length1 - length2);
         if (length1 > length2) {
             pLong = head1;
             pShort = head2;
         } else {
             pLong = head2;
             pShort = head1;
         }
         //长的先走diff
         for(int i = 0; i < diff; i++, pLong = pLong.next) {};
         for(; pLong != pShort; pLong = pLong.next, pShort = pShort.next) {};
         return pLong;
     }

 

子问题二:两有环链表是否相交

问题分析:对于两有环链表可能会出现如下三种情形:

 

上述三种情形中第一种为两链表入环结点相同,后两种入环结点不同。

因此可以采取如下的算法:

第一步: 获得两链表的入环结点

第二步:如两入环结点相同,该问题就可以转化为无环链表的相交结点问题,只不过此时的最后一个结点为相交结点,之前的为null而已。如入环结点不同,则可以从list1的入环结点往下遍历,遍历过程中能遇到list2的入环结点则可得两链表相交,两入环结点均可作为相交的第一个节点,否则不相交。

实现代码如下:

 public class LoopListCommonElement {
     public static Node<Integer> selution(Node<Integer> head1, Node<Integer> head2){
         Node<Integer> loopHead1 = LoopList.selution1(head1);
         Node<Integer> loopHead2 = LoopList.selution1(head2);
         if (loopHead1 != loopHead2) {
             Node<Integer> pTemp = loopHead1.next;
             while (pTemp != loopHead1) {
                 if (pTemp == loopHead2) {
                     break;
                 }
                 pTemp = pTemp.next;
             }
             if (pTemp == loopHead2) {
                 return pTemp;
             }else {
                 return null;
             }
         }else {   // 入环结点相同的情况
             return findCommonHead(head1, head2, loopHead1);
         }
     }
     public static Node<Integer> findCommonHead(Node<Integer> head1, 
         Node<Integer> head2, Node<Integer> end){
         int length1 = 0, length2 = 0;
         for (Node<Integer> p = head1; p != end; p = p.next, length1++) {};
         for (Node<Integer> p = head2; p != end; p = p.next, length2++) {};
         Node<Integer> pLong, pShort;
         int diff = Math.abs(length1 - length2);
         if (length1 > length2) {
             pLong = head1;
             pShort = head2;
         } else {
             pLong = head2;
             pShort = head1;
         }
         for(int i = 0; i < diff; i++, pLong = pLong.next) {};
         for(; pLong != pShort; pLong = pLong.next, pShort = pShort.next) {};
         return pLong;
     }

至此,问题解决。(q:别急还有一个链表有环一个链表无环的情况你没考虑,ps:我赌他们一定不相交你信不信)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值