題目:輸入兩個連結串列,找出它們的第一個公共結點
阿新 • • 發佈:2019-01-29
題目:輸入兩個連結串列,找出它們的第一個公共結點。連結串列的定義如下:
struct ListNode
{
int m_nValue;
ListNode* m_pNext;
};
看到這道題的時候,很多人的第一反應就是採用蠻力的方法:在第一個連結串列上順序遍歷每個節點,每遍歷到一個節點的時候,在第二個連結串列上順序遍歷每個節點。如果第二個連結串列上的節點和第一個連結串列上的節點一樣,就說明兩個連結串列在節點上重合,於是就找到了公共的節點。而通常蠻力並不是好的方法。
從連結串列的定義可以看出,這兩個連結串列是單鏈表,如果兩個連結串列有公共節點,那麼這兩個連結串列從某一節點開始,它們的m_pNext 都指向同一個節點,之後它們所有的節點都是重合的,不可能再出現分叉。所以拓撲形狀看起來是Y型。如下圖所示:
一個簡單的方法是:首先遍歷兩個連結串列得到它們的長度,就能知道哪個連結串列比較長,以及長的連結串列比短的連結串列多幾個節點。在第二次遍歷的時候,先在較長的節點上走若干步,接著同時在兩個連結串列上遍歷,找到的第一個相同的節點就是它們的公共的節點。該演算法的時間複雜度為:O(m+n)。
完整程式碼及其測試用例如下:
#include<iostream> using namespace std; struct ListNode { int m_nValue; ListNode* m_pNext; }; //建立連結串列節點 ListNode* CreateListNode(int value) { ListNode* pNode = new ListNode(); pNode->m_nValue = value; pNode->m_pNext = NULL; return pNode; } //連線連結串列節點 void ConnectListNodes(ListNode* pCurrent, ListNode* pNext) { if (pCurrent == NULL) { //exit(1),非正常執行導致退出程式;exit(0),正常執行並退出程式 cout << "Error to connect two nodes." << endl; exit(1); } pCurrent->m_pNext = pNext; } //銷燬連結串列 void DestroyList(ListNode* pHead) { ListNode* pNode = pHead; while (pNode!=NULL) { pHead = pHead->m_pNext; delete pNode; pNode = pHead; } } //銷燬節點 void DestroyNode(ListNode* pNode) { delete pNode; pNode = NULL; } //求連結串列的長度 unsigned int GetListLength(ListNode* pHead) { unsigned int nLength = 0; ListNode* pNode = pHead; while (pNode!=NULL) { nLength++; pNode = pNode->m_pNext; } return nLength; } //找第一個公共節點 ListNode* FindFirstCommonNode(ListNode *pHead1, ListNode *pHead2) { //求兩個連結串列的長度 unsigned int nLength1 = GetListLength(pHead1); unsigned int nLength2 = GetListLength(pHead2); //兩個連結串列的長度差 int nLengthDif = nLength1 - nLength2; ListNode* pListHeadLong = pHead1; ListNode* pListHeadShort= pHead2; if (nLength2 > nLength1) { pListHeadLong = pHead2; pListHeadShort = pHead1; nLengthDif = nLength2 - nLength1; } // 先在長連結串列上走幾步,再同時在兩個連結串列上遍歷 for (int i = 0; i < nLengthDif; i++) { pListHeadLong = pListHeadLong->m_pNext; } while ((pListHeadLong!=NULL)&& (pListHeadShort != NULL)&&(pListHeadLong != pListHeadShort)) { pListHeadLong = pListHeadLong->m_pNext; pListHeadShort = pListHeadShort->m_pNext; } //得到第一個公共節點 ListNode* pFisrtCommonNode = pListHeadLong; //ListNode* pFisrtCommonNode = pListHeadShort;也可以 return pFisrtCommonNode; } // ====================測試程式碼==================== void Test(char* testName, ListNode* pHead1, ListNode* pHead2, ListNode* pExpected) { if (testName != NULL) { cout << testName << " begins: "; } ListNode* pResult = FindFirstCommonNode(pHead1, pHead2); if (pResult == pExpected) { cout << "Succeed!" << endl; } else { cout << "Failed!" << endl; } } // 第一個公共結點在連結串列中間 // 1 - 2 - 3 \ // 6 - 7 // 4 - 5 / void Test1() { ListNode* pNode1 = CreateListNode(1); ListNode* pNode2 = CreateListNode(2); ListNode* pNode3 = CreateListNode(3); ListNode* pNode4 = CreateListNode(4); ListNode* pNode5 = CreateListNode(5); ListNode* pNode6 = CreateListNode(6); ListNode* pNode7 = CreateListNode(7); ConnectListNodes(pNode1, pNode2); ConnectListNodes(pNode2, pNode3); ConnectListNodes(pNode3, pNode6); ConnectListNodes(pNode4, pNode5); ConnectListNodes(pNode5, pNode6); ConnectListNodes(pNode6, pNode7); Test("Test1", pNode1, pNode4, pNode6); DestroyNode(pNode1); DestroyNode(pNode2); DestroyNode(pNode3); DestroyNode(pNode4); DestroyNode(pNode5); DestroyNode(pNode6); DestroyNode(pNode7); } // 沒有公共結點 // 1 - 2 - 3 - 4 // // 5 - 6 - 7 void Test2() { ListNode* pNode1 = CreateListNode(1); ListNode* pNode2 = CreateListNode(2); ListNode* pNode3 = CreateListNode(3); ListNode* pNode4 = CreateListNode(4); ListNode* pNode5 = CreateListNode(5); ListNode* pNode6 = CreateListNode(6); ListNode* pNode7 = CreateListNode(7); ConnectListNodes(pNode1, pNode2); ConnectListNodes(pNode2, pNode3); ConnectListNodes(pNode3, pNode4); ConnectListNodes(pNode5, pNode6); ConnectListNodes(pNode6, pNode7); Test("Test2", pNode1, pNode5, NULL); DestroyList(pNode1); DestroyList(pNode5); } // 公共結點是最後一個結點 // 1 - 2 - 3 - 4 \ // 7 // 5 - 6 / void Test3() { ListNode* pNode1 = CreateListNode(1); ListNode* pNode2 = CreateListNode(2); ListNode* pNode3 = CreateListNode(3); ListNode* pNode4 = CreateListNode(4); ListNode* pNode5 = CreateListNode(5); ListNode* pNode6 = CreateListNode(6); ListNode* pNode7 = CreateListNode(7); ConnectListNodes(pNode1, pNode2); ConnectListNodes(pNode2, pNode3); ConnectListNodes(pNode3, pNode4); ConnectListNodes(pNode4, pNode7); ConnectListNodes(pNode5, pNode6); ConnectListNodes(pNode6, pNode7); Test("Test3", pNode1, pNode5, pNode7); DestroyNode(pNode1); DestroyNode(pNode2); DestroyNode(pNode3); DestroyNode(pNode4); DestroyNode(pNode5); DestroyNode(pNode6); DestroyNode(pNode7); } // 公共結點是第一個結點 // 1 - 2 - 3 - 4 - 5 // 兩個連結串列完全重合 void Test4() { ListNode* pNode1 = CreateListNode(1); ListNode* pNode2 = CreateListNode(2); ListNode* pNode3 = CreateListNode(3); ListNode* pNode4 = CreateListNode(4); ListNode* pNode5 = CreateListNode(5); ConnectListNodes(pNode1, pNode2); ConnectListNodes(pNode2, pNode3); ConnectListNodes(pNode3, pNode4); ConnectListNodes(pNode4, pNode5); Test("Test4", pNode1, pNode1, pNode1); DestroyList(pNode1); } // 輸入的兩個連結串列有一個空連結串列 void Test5() { ListNode* pNode1 = CreateListNode(1); ListNode* pNode2 = CreateListNode(2); ListNode* pNode3 = CreateListNode(3); ListNode* pNode4 = CreateListNode(4); ListNode* pNode5 = CreateListNode(5); ConnectListNodes(pNode1, pNode2); ConnectListNodes(pNode2, pNode3); ConnectListNodes(pNode3, pNode4); ConnectListNodes(pNode4, pNode5); Test("Test5", NULL, pNode1, NULL); DestroyList(pNode1); } // 輸入的兩個連結串列都是空連結串列 void Test6() { Test("Test6", NULL, NULL, NULL); } int main() { Test1(); Test2(); Test3(); Test4(); Test5(); Test6(); system("pause"); return 0; }
執行結果:
Test1 begins: Succeed!
Test2 begins: Succeed!
Test3 begins: Succeed!
Test4 begins: Succeed!
Test5 begins: Succeed!
Test6 begins: Succeed!
請按任意鍵繼續. . .