【剑指offer】两个链表的第一个公共节点

    xiaoxiao2021-03-28  32

    摘要

    剑指offer面试题 37  : 给两个单链表链表 ,,,找出他们的第一个相遇节点 链表节点的定义如下: //链表节点的定义 struct ListNode { int _data; ListNode* _next; };

    实现方法

    看到这道题的第一感觉就是死方法,,,;;; 在第一个链表的   逐步遍历链表节点,,,, 每遍历一个节点的时候   ,,,,同时顺序遍历链表2 的每一各节点 此种做法的时间复杂度就是有点大了   O(M+N) 代码的实现 //方法1 死方法 直接遍历两个链表 ,,,,这样的做法的时间复杂度为O(M*N) ListNode* GetMeetNode1(ListNode* head1,ListNode* head2) { ListNode * cur1 =head1; while(cur1)//遍历链表1 { ListNode* cur2 = head2;//顺序遍历链表2 while(cur2) { if(cur1 == cur2)//要是两个节点相同,,表示就是第一个相遇节点 { return cur1; } cur2 =cur2->_next; } cur1= cur1->_next; } return NULL;//表示的是两个链表没有相遇节点 } 上面的做法只是一般人    的做法;;; 你要是觉得你不是一般人的话 ,,,,就往下来看    上面的代码的时间复杂度有点大了  。。。。。 但是我们要怎么来减少时间复杂度呢  ??????????? 我们都知道   两个链表的相交一般就是两种情况  ::: Y型相交; V型相交。。。。 这两种相交的情形都有一个共同点 ;;;; 他们的尾节点都是一样的。。。。 所以我们可以从尾部向前来判断,,,,找到最后的一个相同的节点  就是   所谓的第一个相遇节点。。。。 但是要  ,,实现这种的操作的;;我们就必须先找到最后一个节点 ,,,,并把前面的节点保存起来。。。。 这个有点像是     "后进先出"的原则。。。。。 所以我们想到了用栈来实现  。。。。。这也就是所谓的以空间来换取时间的做法 这样的时间复杂度就是O(M+N)  空间复杂度为O(M+N);;; 代码的实现 //方法2: 两个链表的相交有两种的方式 //1、Y型相交 //2、V型相交 //我们可以看到这两种情况 都有一个共同点:他们两个的尾节点重合 //我们只要从后往前两遍历 最后一个相同的节点就是他们的相遇节点 //时间复杂度的最坏的情况为O(M+N+N) //但是空间复杂度有点大 #include<stack> ListNode* GetMeetNode2(ListNode* head1,ListNode* head2) { ListNode * cur1 = head1; ListNode * cur2 = head2; //若要从后往前来判断 ,,,就是一种后进先出的想法;;;使用栈 stack<ListNode*> s1;//用来保存两个链表的值 stack<ListNode*> s2; while(cur1)//存储链表1 { s1.push(cur1); cur1= cur1 ->_next; } while(cur2)//存储链表2 { s2.push(cur2); cur2= cur2 ->_next; } cur1 = s1.top(); cur2 = s2.top(); s1.pop(); s2.pop(); if(cur1 != cur2)//表示的是 他们没有相遇节点 return NULL;//表示的是两个链表没有相遇节点 while(cur1 == cur2) { if(!s1.empty() || !s2.empty())//表示的是 链表1结束或者链表2结束 return cur1; cur1 = s1.top(); cur2 = s2.top(); s1.pop(); s2.pop(); } //走到这里cur1 表示的是最后一个不想同的节点 return cur1->_next; } 要是你可以做到这一步的话 ,,那就是也能说明::: 你只是比普通人要好一点 ,,, 但是要是面试的话,,,,面试官肯定还是不满意 。。。。 既然,,,你都能把时间复杂度降下来,,,,,为什么不能把空间复杂度也降下来呢??? 一般的链表的相交的问题就是这个样子的,,图中    我们可以清楚的看到的如果两个链表同分别从      3     和      5 开始向后判断   ,,, 当两个节点相同的时候 ,,,得到的就是第一个相遇节点  但是,,,要是实现这种    解法,,,我们就要    知道怎么得到     3  和  5这两个节点  我们可以来得到两个链表的长度 ,,,先将 让长的链表先走(m-n)部 //方法三:上面的两种情况 不是时间复杂度太高,,就是空间复杂度太大 //所以我们想出了第三种情况 //先得到两个链表的长度 int GetListSize(ListNode* head) { int count = 0 ; while(head) { head = head->_next; count++; } return count; } ListNode* GetMeetNode3(ListNode* head1,ListNode* head2) { //先得到两个链表的长度 int size1 = GetListSize(head1); int size2 = GetListSize(head2); ListNode* longNode = head1;//定义一个长的链表节点 ListNode* shortNode = head2;//定义一个短的链表节点 int n = size1- size2; if(size1 < size2)//做的适量的调整 { n = size2 -size1; longNode =head2; shortNode =head1; } for(int i = 0 ;i < n;++i) { longNode = longNode ->_next; } while(shortNode && longNode &&shortNode!= longNode) { shortNode = shortNode->_next; longNode = longNode->_next; } return shortNode; }      
    转载请注明原文地址: https://ju.6miu.com/read-664768.html

    最新回复(0)