1. 程式人生 > >牛客網《劍指Offer》 程式設計 25.複雜連結串列的複製 (最優解法)

牛客網《劍指Offer》 程式設計 25.複雜連結串列的複製 (最優解法)

題目描述

輸入一個複雜連結串列(每個節點中有節點值,以及兩個指標,一個指向下一個節點,另一個特殊指標指向任意一個節點),返回結果為複製後複雜連結串列的head。(注意,輸出結果中請不要返回引數中的節點引用,否則判題程式會直接返回空)

解題思路

這次使用時間複雜度為O(n),空間複雜度為O(1)的演算法。

首先,在原連結串列的每個節點後面複製相應的連結串列節點,即複製next域。

然後,複製random域。原連結串列中某個節點的random域的下一個節點,就是複製連結串列的random域。

最後,將連結串列拆分成為兩個連結串列。奇數位上的是原連結串列節點,偶數位上的是複製連結串列節點。

程式碼實現

RandomListNode* Clone(RandomListNode* pHead) {
		if (pHead == nullptr) { return nullptr; }
		RandomListNode* currNode = pHead;
		RandomListNode* newNode = nullptr, *newHead = nullptr, *preNode = nullptr;
		//第一次遍歷連結串列,將與原連結串列節點值相同的信連結串列節點放在對應的原連結串列節點後面。
		while (currNode) {
			newNode = new RandomListNode(currNode->label);
			newNode->next = currNode->next;
			currNode->next = newNode;
			currNode = newNode->next;
		}
		currNode = pHead;
		newHead = currNode->next;
		newNode = currNode->next;
		//第二次遍歷,複製random域。
		while (currNode&&newNode) {
			RandomListNode* currRandom = currNode->random;
			if (currRandom) {
				RandomListNode* randomNode = currRandom->next;
				newNode->random = randomNode;
			}
			currNode = currNode->next;
			newNode = newNode->next;
		}
		//第三次遍歷,拆分連結串列。奇數位上的是原連結串列的節點,偶數位上的是複製連結串列的節點。
		currNode = pHead;
		newNode = currNode->next;
		while (currNode&&newNode) {
			currNode->next = newNode->next;
			currNode = currNode->next;
			if (currNode) {
				newNode->next = currNode->next;
				newNode = newNode->next;
			}
		}
		return newHead;
	}

測試用例

列印函式如下所示:先按照順序打印出連結串列的next域,然後打印出連結串列的的radom域。

使用五個測試用例:

1.空連結串列

2.普通複雜連結串列

3.random域指向自身的連結串列

4.只有一個節點的連結串列

5.存在護指節點的連結串列

void print(RandomListNode* head) {//列印函式
			RandomListNode* temp = head;
			while (temp) {
				cout << temp->label << "->";
				temp = temp->next;
			}
			cout << "null";
			cout << endl;
			temp = head;
			while (temp) {
				if (temp->random == nullptr) {
					cout << temp->label << "=>" << "null" << endl;
				}
				else {
					cout << temp->label << "=>" << temp->random->label << endl;
				}
				temp = temp->next;
			}
		}
int main()
{
	//Test1:空連結串列
	RandomListNode* node = nullptr;
	//Test2:普通隨機連結串列
	RandomListNode* node0 = new RandomListNode(0);
	RandomListNode* node1 = new RandomListNode(1);
	RandomListNode* node2 = new RandomListNode(2);
	RandomListNode* node3 = new RandomListNode(3);
	RandomListNode* node4 = new RandomListNode(4);
	node0->next = node1;
	node1->next = node2;
	node2->next = node3;
	node3->next = node4;
	node4->next = nullptr;
	node0->random = node2;
	node1->random = node4;
	node3->random = node1;
	//Test3:random域指向自身
	RandomListNode* node5 = new RandomListNode(5);
	RandomListNode* node6 = new RandomListNode(6);
	node5->next = node6;
	node6->next = nullptr;
	node5->random = node5;
	//Test4:只有一個節點的連結串列
	RandomListNode* node7 = new RandomListNode(7);
	node7->next = nullptr;
	node7->random = node7;
	//Test5:兩個連結串列節點互相指,從而形成環狀
	RandomListNode* node8 = new RandomListNode(8);
	RandomListNode* node9 = new RandomListNode(9);
	RandomListNode* node10 = new RandomListNode(10);
	RandomListNode* node11 = new RandomListNode(11);
	RandomListNode* node12= new RandomListNode(12);
	node8->next = node9;
	node9->next = node10;
	node10->next = node11;
	node11->next = node12;
	node12->next = nullptr;
	node9->random = node11;
	node11->random = node9;
	//判斷是否是值相同的連結串列:先列印連結串列,再列印每個節點的random域。
	cout << "******************Test1:空連結串列測試******************" << endl;
	RandomListNode* ans = Clone(node);
	cout << "原連結串列:" << endl;
	print(node);
	cout << endl;
	cout << "複製連結串列:" << endl;
	print(ans);
	cout << "******************Test2:空連結串列測試******************" << endl;
	RandomListNode* ans0 = Clone(node0);
	cout << "原連結串列:" << endl;
	print(node0);
	cout << endl;
	cout << "複製連結串列:" << endl;
	print(ans0);
	cout << "******************Test3:random域指向自身連結串列測試******************" << endl;
	RandomListNode* ans1 = Clone(node5);
	cout << "原連結串列:" << endl;
	print(node5);
	cout << endl;
	cout << "複製連結串列:" << endl;
	print(ans1);
	cout << "******************Test4:只有一個節點的連結串列測試******************" << endl;
	RandomListNode* ans2 = Clone(node7);
	cout << "原連結串列:" << endl;
	print(node7);
	cout << endl;
	cout << "複製連結串列:" << endl;
	print(ans2);
	cout << "******************Test5:存在兩個節點護指的連結串列測試******************" << endl;
	RandomListNode* ans3 = Clone(node8);
	cout << "原連結串列:" << endl;
	print(node8);
	cout << endl;
	cout << "複製連結串列:" << endl;
	print(ans3);
	return 0;
}

測試結果