1. 程式人生 > >#資料結構與演算法學習筆記#劍指Offer34:兩個連結串列的第一個公共結點 + 等長遍歷/輔助棧 + 測試用例(Java、C/C++)

#資料結構與演算法學習筆記#劍指Offer34:兩個連結串列的第一個公共結點 + 等長遍歷/輔助棧 + 測試用例(Java、C/C++)

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一秒鐘。留個言點個讚唄,謝謝你#