#資料結構與演算法學習筆記#劍指Offer34:兩個連結串列的第一個公共結點 + 等長遍歷/輔助棧 + 測試用例(Java、C/C++)
阿新 • • 發佈:2018-12-16
2018.10.21
這道題也是屬於效率題,實現難度不大,但是要降低複雜度還是需要思考一下。有兩個o(n)的做法:
方法一:等長連結串列法。先計算兩條連結串列的長度,然後先遍歷長連結串列直到兩條連結串列等長,最後依次按奇偶順序挨個遍歷兩條連結串列各個結點。
方法二:輔助棧法(需要開闢棧空間)。注意到連結串列公共結點後的所有結點都是公共的,可以將兩條連結串列元素分別入棧,依次檢驗棧頂元素,最後一個相同的棧頂元素為第一個公共結點。
注意幾個特殊情況:1.只有一個結點,2.短連結串列為長連結串列的子連結串列,3.沒有公共結點
題目描述
輸入兩個連結串列,找出它們的第一個公共結點。
Java實現:
/** * * @author ChopinXBP * 輸入兩個連結串列,找出它們的第一個公共結點。 * */ import java.util.LinkedList; public class FindFirstCommonNode_35 { public static class ListNode { int val; ListNode next = null; ListNode(int val) { this.val = val; } } public static void main(String[] args) { // TODO Auto-generated method stub ListNode Node0 = new ListNode(0); ListNode Node1 = new ListNode(1); ListNode Node2 = new ListNode(2); ListNode Node3 = new ListNode(3); ListNode Node4 = new ListNode(4); ListNode Node5 = new ListNode(5); ListNode Node6 = new ListNode(6); Node0.next = Node1; Node1.next = Node2; Node2.next = Node3; Node3.next = Node4; Node4.next = Node5; Node5.next = Node6; System.out.println(FindFirstCommonNode(Node0, Node6).val); System.out.println(FindFirstCommonNode2(Node0, Node6).val); } //方法1:等長遍歷法(不需要開闢棧空間) public static ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) { if(pHead1 == null || pHead2 == null) return null; if(pHead1 == pHead2) return pHead1; //計算連結串列1的長度 ListNode plong = pHead1; int length1 = 1; while(plong.next != null){ plong = plong.next; length1++; } //計算連結串列2的長度 ListNode pshort = pHead2; int length2 = 1; while(pshort.next != null){ pshort = pshort.next; length2++; } //確定連結串列長短與差值num int num; if(length1 > length2){ plong = pHead1; pshort = pHead2; num = length1 - length2; }else{ plong = pHead2; pshort = pHead1; num = length2 - length1; } //遍歷長連結串列前num個結點,使兩連結串列等長 while(num-- > 0){ if(plong == pshort)return plong; plong = plong.next; } //依次遍歷兩個連結串列的每一個結點,num用於奇偶標誌 num = 0; while(plong.next != null || pshort.next != null){ if(plong == pshort) return plong; if((num & 0x01) == 0){ plong = plong.next; }else{ pshort = pshort.next; } num++; } if(plong == pshort)return plong; return null; } //方法2:輔助棧法 public static ListNode FindFirstCommonNode2(ListNode pHead1, ListNode pHead2) { if(pHead1 == null || pHead2 == null) return null; if(pHead1 == pHead2) return pHead1; //元素入棧 LinkedList<ListNode> p1stack = new LinkedList<>(); LinkedList<ListNode> p2stack = new LinkedList<>(); ListNode pListNode = pHead1; while(pListNode != null){ p1stack.add(pListNode); pListNode = pListNode.next; } pListNode = pHead2; while(pListNode != null){ p2stack.add(pListNode); pListNode = pListNode.next; } //依次檢驗棧頂元素。如果棧頂元素不想等直接返回初始的pListNode,此時的pListNode為null while(!p1stack.isEmpty() && !p2stack.isEmpty()){ if(p1stack.getLast() == p2stack.getLast()){ pListNode = p1stack.getLast(); p1stack.pollLast(); p2stack.pollLast(); if(p1stack.isEmpty() || p2stack.isEmpty()) return pListNode; }else{ return pListNode; } } return null; } }
C++實現示例(方法一):
class Solution { public: ListNode* FindFirstCommonNode( ListNode *pHead1, ListNode *pHead2) { int len1 = findListLenth(pHead1); int len2 = findListLenth(pHead2); if(len1 > len2){ pHead1 = walkStep(pHead1,len1 - len2); }else{ pHead2 = walkStep(pHead2,len2 - len1); } while(pHead1 != NULL){ if(pHead1 == pHead2) return pHead1; pHead1 = pHead1->next; pHead2 = pHead2->next; } return NULL; } int findListLenth(ListNode *pHead1){ if(pHead1 == NULL) return 0; int sum = 1; while(pHead1 = pHead1->next) sum++; return sum; } ListNode* walkStep(ListNode *pHead1, int step){ while(step--){ pHead1 = pHead1->next; } return pHead1; } };
測試程式碼:
// ====================測試程式碼====================
void DestroyNode(ListNode* pNode);
void Test(char* testName, ListNode* pHead1, ListNode* pHead2, ListNode* pExpected)
{
if(testName != NULL)
printf("%s begins: ", testName);
ListNode* pResult = FindFirstCommonNode(pHead1, pHead2);
if(pResult == pExpected)
printf("Passed.\n");
else
printf("Failed.\n");
}
// 第一個公共結點在連結串列中間
// 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);
}
void DestroyNode(ListNode* pNode)
{
delete pNode;
pNode = NULL;
}
int _tmain(int argc, _TCHAR* argv[])
{
Test1();
Test2();
Test3();
Test4();
Test5();
Test6();
return 0;
}
#Coding一小時,Copying一秒鐘。留個言點個讚唄,謝謝你#