题目:输入两个链表,找出它们的第一个公共结点。
思路1:暴力查找法。将链表1中的节点逐个与链表2中的所有节点比较,返回第一个相同的节点。复杂度O(mn)
class Solution { public: ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) { if(pHead1 == nullptr || pHead2 == nullptr){ return nullptr; } ListNode* pNode1 = pHead1; ListNode* pNode2 = pHead2; ListNode* pCommonNode = nullptr; while(pNode1->next != nullptr){ while(pNode2->next !=nullptr){ if(pNode1 != pNode2){ pNode2 = pNode2->next; } else{ pCommonNode = pNode1; return pCommonNode; break; } } if(pCommonNode != nullptr){ break; } else{ pNode1 = pNode1->next; } } return pCommonNode; } };
上述代码没有通过测试用例:具体原因是什么呢???
思路2:上述方法的复杂度过高,并不是一个好方法。如果两个链表有公共点,那么公共节点出现在两个链表的尾部。如果从两个链表的尾部开始往前比较,那么最后一个相同的节点就是我们要找的节点。因为要从尾部开始比较,所以可以利用栈结构的“后进后出”:分别把两个链表的节点放入两个栈中,这样两个栈的尾节点就位于两个栈的栈顶,接下来比较两个栈顶的节点是否相同,相同则把栈顶弹出接着比较下一个栈顶,直到找到最后一个相同节点。这种方法是用空间消耗换取了时间效率。
class Solution { public: ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) { if(pHead1 == nullptr || pHead2 == nullptr){ return nullptr; } std::stack<ListNode*> stack1; std::stack<ListNode*> stack2; while(pHead1 != nullptr){ stack1.push(pHead1); pHead1=pHead1->next; } while(pHead2 != nullptr){ stack2.push(pHead2); pHead2=pHead2->next; } ListNode* commonNode = nullptr; while(!stack1.empty() && !stack2.empty()){ if(stack1.top() == stack2.top()){ commonNode = stack1.top(); stack1.pop(); stack2.pop(); } } return commonNode; } };
报错:
思路3:首先遍历两个链表得到它们的长度,就能知道哪个链表比较长,以及长得链表比短的链表多几个节点。在第二次遍历的时候,在较长的链表上先走若干步,接着同时在两个链表上遍历,找到的第一个相同的节点就是它们的第一个公共节点。
class Solution { public: ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) { unsigned int nLength1 = GetListLength(pHead1); unsigned int nLength2 = GetListLength(pHead2); int nLengthDif = nLength1 - nLength2; ListNode* pListNodeLong = pHead1; ListNode* pListNodeShort = pHead2; if(nLength2>nLength1){ pListNodeLong = pHead2; pListNodeShort = pHead1; nLengthDif = nLength2 - nLength1; } for(int i = 1;i<nLengthDif+1;i++){ pListNodeLong = pListNodeLong->next; } while(pListNodeLong != nullptr && pListNodeShort != nullptr && pListNodeShort != pListNodeLong){ pListNodeLong = pListNodeLong->next; pListNodeShort = pListNodeShort->next; } ListNode* pFirstCommonNode = pListNodeLong; return pFirstCommonNode; } private: unsigned int GetListLength(ListNode * pHead){ unsigned int nLength = 0; ListNode* pNode = pHead; while(pNode != nullptr){ nLength++; pNode = pNode->next; } return nLength; } };