剑指offer -- 两个链表的第一个公共节点(普通解法+辅助栈解法+双指针两种解法)

题目:
输入两个链表,找出他们的第一个公共节点。链表节点定义如下:

  struct ListNode {
    
    
    int val;
    ListNode *next;
  };

分析:
解法一
在第一个链表上顺序遍历每个节点,每遍历到一个节点,就在第二个链表上顺序遍历每个节点,如果在第二个链表上有一个节点和第一个链表上的节点一样,那么这个节点就是我们要找的公共节点如果第一个链表长度为m,第二个链表长度为n,那么显然该方法的时间复杂度为O(mn),一般情况下暴力法都不会是最好的解决办法。
解法二:
我们试着分析有公共节点的两个链表有哪些特点。两个链表如果有公共节点,那么这两个链表从某个节点开始他们的pNext都指向一个节点,由于是单向链表,每个节点只有一个pNext,从第一个公共链表开始,他们之后的所有的节点都是重合的,不可能再出现分叉。则如果两个链表有公共节点,从两个链表的尾部开始向前比较,那么最后一个相同的节点就是我们要找的节点,可问题是单向链表,我们只能从头节点开始遍历按顺序最后到达尾结点,可是我们却想最先开始比较尾结点,这种顺序结构跟我们学过的栈相同,我们把两个链表分别放到两个栈里,这样两个链表的尾结点就出现在栈顶,比较栈顶节点是否相同,如果相等,则弹出栈顶比较下一个栈顶,直到找到最后一个相同的节点。空间复杂度为O(m+n),时间复杂度也是O(m+n)。跟法一相比相当于用空间换取时间。

ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
    
    
        stack<ListNode*>sta1;
        stack<ListNode*>sta2;
    
        ListNode *p1 = headA;
        ListNode *p2 = headB;
       
        while(p1 != NULL){
    
    
            sta1.push(p1);
            p1 = p1->next;
        }
        while(p2 != NULL){
    
    
            sta2.push(p2);
            p2 = p2->next;
        }
        while(!sta1.empty() && !sta2.empty()){
    
    
               if(sta1.top() == sta2.top()){
    
    
                   p1 = sta1.top();
                   sta1.pop();
                   sta2.pop();
               }
               else
               break;
        }
        return p1;
    
    }

解法三:我们先遍历两个链表得到他们各自的长度,链表1比链表2长x, 那我们再次遍历两个链表的时候先让链表1的指针走x步,然后两个链表的指针再一起走,当两个指针指向的节点相等的时候,我们就找到了公共节点。时间复杂度O(m+n)。

ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
    
    
        ListNode *p1 = headA;
        ListNode *p2 = headB;
        int count1 = 0;
        int count2 = 0;
        int x = 0;

        while(p1 != NULL){
    
    
            count1++;
            p1 = p1->next;
        }
        while(p2 != NULL){
    
    
            count2++;
            p2 = p2->next;
        }
        p1 = headA;
        p2 = headB;

        if(count1 >= count2){
    
    
          while(x != count1 - count2){
    
    
               p1 = p1->next;
               x++;
           }
           while(p1 != p2){
    
    
               p1 = p1->next;
               p2 = p2->next;
           }
       }
        else {
    
    
           while(x != count2 - count1){
    
    
             p2 = p2->next;
             x++;
          }
          while(p1 != p2) {
    
    
              p1 = p1->next;
              p2 = p2->next;
          }
     }
       
    return p1;
  
    }

但是其实这种解法还有另一种思路,不用先遍历得到两个链表的长度,直接让两个指针从各自链表的头开始遍历,如果其中一个链表的指针为空了,那就让它接着从另一个链表的头开始走,直到两个指针指向的节点相等。即a+c+b=b+c+a。
在这里插入图片描述

ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
    
    
        ListNode *p1 = headA;
        ListNode *p2 = headB;

        while(p1 != p2)
        {
    
    
            if(p1 == NULL)
            {
    
    
                 p1 = headB;
            }
            else
            {
    
    
                p1 = p1->next;

            }
           
            if(p2 == NULL)
            {
    
    
                p2 = headA;
            }
            else
            {
    
    
                p2 = p2->next;
            }  
        }
        return p1;
    }

おすすめ

転載: blog.csdn.net/scarificed/article/details/120625324