每日一题(68) - 复杂链表的复制

题目和思路来自剑指Offer

题目

每日一题(68) - 复杂链表的复制_第1张图片

举例

每日一题(68) - 复杂链表的复制_第2张图片

思路:难点是怎么确定兄弟指针的指向。

思路(1)使用Map确定兄弟指针的指向

如上例,输入数据为 A,B,C,D、E

建立的map:

A - A'

B - B'

...

E - E'

初始化兄弟结点的值:

以结点A为例,要寻找结点A'的兄弟结点D'

遍历已有链表的结点A时,找到其兄弟结点D,之后根据Map,获得D',这里D'就是新链表结点A'的兄弟结点

这里,空间复杂度为O(n),时间复杂度为O(n),假设map查找时间为O(1)。

代码

#include <iostream>
#include <map>
#include <assert.h>
using namespace std;

struct Node
{
	int m_nValue;
	Node* m_pNext;
	Node* m_pSbling;
};

/*根据已知链表,创建新链表,此时兄弟指针赋空*/
Node* CreatNewList(Node* pHead,map<Node*,Node*>& mapCloneNode)
{
	Node* pNewHead = NULL; 
	Node* pLastNew = NULL;
	Node* pCur = pHead;

	while (pCur)
	{
		//创建链表
		Node* pNewNode = new Node;
		pNewNode->m_nValue = pCur->m_nValue;
		pNewNode->m_pSbling = NULL;
		pNewNode->m_pNext = NULL;

		if (!pNewHead)
		{
			pNewHead = pNewNode;
		}
		else
		{
			pLastNew->m_pNext = pNewNode;
		}
		pLastNew = pNewNode;
		//把链表插入map
		mapCloneNode.insert(make_pair(pCur,pNewNode));

		pCur = pCur->m_pNext;
	}
	return pNewHead;
}
/*根据A,查找A'*/
Node* FindNew(map<Node*,Node*>& mapCloneNode,Node* pNode)
{
	if (pNode == NULL)
	{
		return NULL;
	}
	map<Node*,Node*>::iterator itCur = mapCloneNode.find(pNode);
	if (itCur != mapCloneNode.end())
	{
		return itCur->second;
	}
	else
	{
		return NULL;
	}
}

/*根据A,查找A的兄弟*/
void FindSbling(map<Node*,Node*>& mapCloneNode,Node* pHead,Node* pNewHead)
{
	Node* pCur = pHead;
	Node* pCurSbling = NULL;
	Node* pCurNew = pNewHead;

	while(pCur)
	{
		pCurNew->m_pSbling = FindNew(mapCloneNode,pCur->m_pSbling);

		pCur = pCur->m_pNext;
		pCurNew = pCurNew->m_pNext;
	}
}
/*主函数*/
Node* Clone(Node* pHead)
{
	assert(pHead);
	map<Node*,Node*> mapCloneNode;
	Node* pNewHead = CreatNewList(pHead,mapCloneNode); //创建新链表,但兄弟指针赋空
	FindSbling(mapCloneNode,pHead,pNewHead);//获得兄弟指针
	return pNewHead;
}

void Print(Node* pHead)
{
	Node* pCur = pHead;
	while(pCur)
	{
		cout<<pCur->m_nValue<<" ";
		if (pCur->m_pSbling)
		{
			cout<<pCur->m_pSbling->m_nValue<<endl;
		}
		else
		{
			cout<<0<<endl;
		}

		pCur = pCur->m_pNext;
	}
	cout<<endl;
}

Node* CreatList()
{
	int nLen = 0;
	int nSblingData = 0;
	cin >> nLen;
	//创建结点
	Node* pHead = NULL;
	Node* pNew = NULL;
	Node* pLast = NULL;
	for (int i = 0;i < nLen;i++)
	{
		pNew = new Node;
		cin>>pNew->m_nValue;
		pNew->m_pNext = NULL;
		pNew->m_pSbling = NULL;

		if (pHead == NULL)
		{
			pHead = pNew;
		}
		else
		{
			pLast->m_pNext = pNew;
		}
		pLast = pNew;
	}
	//创建兄弟
	Node* pCur = pHead;
	Node* pCurTmp = pHead;

	while(pCur)
	{
		cin>>nSblingData;//接受兄弟的下标
		pCurTmp = pHead;
		if (nSblingData == 0)
		{
			pCur->m_pSbling = NULL;
		}
		else
		{
			while(pCurTmp && nSblingData != pCurTmp->m_nValue)
			{
				pCurTmp = pCurTmp->m_pNext;
			}
			assert(pCurTmp);
			pCur->m_pSbling = pCurTmp;
		}
		pCur = pCur->m_pNext;
	}
	return pHead;
}

int main()
{
	Node* pHead = NULL;
	Node* pNewHead = NULL;
	pHead = CreatList();
	Print(pHead);
	pNewHead = Clone(pHead);
	Print(pHead);
	system("pause");
	return 1;
}
这里借用王道论坛的测试用例:题目1524:复杂链表的复制

附加带环的测试用例

输入:

5

1 2 3 4 5

3 2 1 5 4

输出:

1 3

2 2

3 1

4 5

5 4

思路(2)在旧链表中创建新链表,之后再从旧链表中拆分得到新链表

具体分为三步:

(1)在旧链表中创建新链表,此时不处理新链表的兄弟结点

每日一题(68) - 复杂链表的复制_第3张图片

(2)根据旧链表的兄弟结点,初始化新链表的兄弟结点

每日一题(68) - 复杂链表的复制_第4张图片

(3)从旧链表中拆分得到新链表

每日一题(68) - 复杂链表的复制_第5张图片

代码:

#include <iostream>
#include <map>
#include <assert.h>
using namespace std;

struct Node
{
	int m_nValue;
	Node* m_pNext;
	Node* m_pSbling;
};

/*根据已知链表,创建新链表,此时兄弟指针赋空*/
void CreatNewList(Node* pHead)
{
	assert(pHead);
	Node* pCur = pHead;
	while (pCur)
	{
		//创建链表
		Node* pNewNode = new Node;
		pNewNode->m_nValue = pCur->m_nValue;
		pNewNode->m_pSbling = NULL;
		pNewNode->m_pNext = pCur->m_pNext;
		pCur->m_pNext = pNewNode;

		pCur = pCur->m_pNext->m_pNext;
	}
}

/*根据A,查找A的兄弟*/
void InitSbling(Node* pHead)
{
	assert(pHead);
	Node* pCur = pHead;
	Node* pCurNext = NULL;

	while(pCur)
	{
		pCurNext = pCur->m_pNext;
		if (pCur->m_pSbling)
		{
			pCurNext->m_pSbling = pCur->m_pSbling->m_pNext;

		}
		pCur = pCur->m_pNext->m_pNext;
	}
}

Node* SeparateList(Node* pHead)
{
	assert(pHead);
	Node* pNewHead = NULL;
	Node* pCur = pHead;
	Node* pLastNew = NULL;
	while(pCur)
	{
		if (pNewHead == NULL)
		{
			pNewHead = pCur->m_pNext;
		}
		else
		{
			pLastNew->m_pNext = pCur->m_pNext;
		}
		pLastNew = pCur->m_pNext;

		pCur->m_pNext = pCur->m_pNext->m_pNext;
		pCur = pCur->m_pNext;		
	}
	return pNewHead;
}

/*主函数*/
Node* Clone(Node* pHead)
{
	assert(pHead);
	CreatNewList(pHead); //创建新链表,但兄弟指针赋空
	InitSbling(pHead);
	return SeparateList(pHead);
}

void Print(Node* pHead)
{
	Node* pCur = pHead;
	while(pCur)
	{
		cout<<pCur->m_nValue<<" ";
		if (pCur->m_pSbling)
		{
			cout<<pCur->m_pSbling->m_nValue<<endl;
		}
		else
		{
			cout<<0<<endl;
		}

		pCur = pCur->m_pNext;
	}
	cout<<endl;
}

Node* CreatList()
{
	int nLen = 0;
	int nSblingData = 0;
	cin >> nLen;
	//创建结点
	Node* pHead = NULL;
	Node* pNew = NULL;
	Node* pLast = NULL;
	for (int i = 0;i < nLen;i++)
	{
		pNew = new Node;
		cin>>pNew->m_nValue;
		pNew->m_pNext = NULL;
		pNew->m_pSbling = NULL;

		if (pHead == NULL)
		{
			pHead = pNew;
		}
		else
		{
			pLast->m_pNext = pNew;
		}
		pLast = pNew;
	}
	//创建兄弟
	Node* pCur = pHead;
	Node* pCurTmp = pHead;

	while(pCur)
	{
		cin>>nSblingData;//接受兄弟的下标
		pCurTmp = pHead;
		if (nSblingData == 0)
		{
			pCur->m_pSbling = NULL;
		}
		else
		{
			while(pCurTmp && nSblingData != pCurTmp->m_nValue)
			{
				pCurTmp = pCurTmp->m_pNext;
			}
			assert(pCurTmp);
			pCur->m_pSbling = pCurTmp;
		}
		pCur = pCur->m_pNext;
	}
	return pHead;
}

int main()
{
	Node* pHead = NULL;
	Node* pNewHead = NULL;
	pHead = CreatList();
	Print(pHead);
	pNewHead = Clone(pHead);
	Print(pHead);
	system("pause");
	return 1;
}
测试用例如方法一,完。

你可能感兴趣的:(每日一题(68) - 复杂链表的复制)