剑指Offer面试题(第二十一天)面试题35

 * 面试题35:复杂链表的复制


     *题目:请实现函数complexListNode* Clone(ComplexListNode* pHead),
     *     复制一个复杂链表。在复杂链表中,每个节点除了有一个m_pNext指针指向下一个节点,还有一个m_pSibling指针指向链表中的任意节点或者null指针。
     *C++中节点定义为:
     *struct ComplexListNode{
     *    int m_nValue;
     *    ComplexListNode* m_pNext;
     *    ComplexListNode* m_pSibsling;
     *}
     *
     *第一种办法:
     *思路:1>复制每一个节点N为N',并指向next
     *     2>构建N'的sibling节点S'(从头查找sibling节点)
     *时间复杂度O(n2)  空间复杂度O(1)
     *
     *第二种办法:
     *思路:1>复制每一个节点N为N',并指向next,构建一个哈希表,存储<N,N'>的配对信息
     *     2>构建N'的sibling节点S',直接查找哈希表,即可找到S'
     *时间复杂度O(n)   空间复杂度O(n)   
     *
     *第三种办法: (下面实现的)
     *思路:1>将每个节点N进行复制为N',然后连接到每个N的next下
     *   2>然后根据每个N的sibling节点S,连接N’的sibling节点S',也就是S.sibling
     *   3>最后再将奇数个的节点连接到一起,就是原链表;将偶数个的节点连接到一起,就是复制的节点
     *   时间复杂度O(n)  空间复杂度O(1) 

package Test;

public class No35CopyComplexList {

	/*
	 * 面试题35:复杂链表的复制
	 *题目:请实现函数complexListNode* Clone(ComplexListNode* pHead),
	 *	 复制一个复杂链表。在复杂链表中,每个节点除了有一个m_pNext指针指向下一个节点,还有一个m_pSibling指针指向链表中的任意节点或者null指针。
	 *C++中节点定义为:
	 *struct ComplexListNode{
	 *	int m_nValue;
	 *	ComplexListNode* m_pNext;
	 *	ComplexListNode* m_pSibsling;
	 *}
	 *
	 *第一种办法:
	 *思路:1>复制每一个节点N为N',并指向next
	 *	 2>构建N'的sibling节点S'(从头查找sibling节点)
	 *时间复杂度O(n2)  空间复杂度O(1)
	 *
	 *第二种办法:
	 *思路:1>复制每一个节点N为N',并指向next,构建一个哈希表,存储<N,N'>的配对信息
	 *	 2>构建N'的sibling节点S',直接查找哈希表,即可找到S'
	 *时间复杂度O(n)   空间复杂度O(n)   
	 *
	 *第三种办法: (下面实现的)
	 *思路:1>将每个节点N进行复制为N',然后连接到每个N的next下
	 *   2>然后根据每个N的sibling节点S,连接N’的sibling节点S',也就是S.sibling
	 *   3>最后再将奇数个的节点连接到一起,就是原链表;将偶数个的节点连接到一起,就是复制的节点
	 *   时间复杂度O(n)  空间复杂度O(1) 
	 *    
	 * */
	
	//复杂链表指针
	static class ComplexListNode{
		int val;
		ComplexListNode next;
		ComplexListNode sibling;
		
		ComplexListNode(int val){
			this.val = val;
		}
	}
	public static void main(String[] args) {
		// TODO Auto-generated method stub

		No35CopyComplexList c = new No35CopyComplexList();
		
		ComplexListNode root = new ComplexListNode(1);
		ComplexListNode two = new ComplexListNode(2);
		ComplexListNode three = new ComplexListNode(3);
		ComplexListNode four = new ComplexListNode(4);
		ComplexListNode five = new ComplexListNode(5);
		
		root.next = two;
		root.sibling = three;
		
		two.next = three;
		two.sibling = five;
		
		three.next = four;
		three.sibling = null;
		
		four.next = five;
		four.sibling = two;
		
		five.next = null;
		five.sibling = null;
		
		//复制复杂链表
		ComplexListNode result = c.Clone(root);
		ComplexListNode print = result;
		System.out.println("输出每个节点的sibling节点:");
		
		while(print != null) {
			if(print.sibling != null) {
				System.out.println(print.val + "的sibling节点为:"+print.sibling.val);
			}
			print = print.next;
		}
			
	}
	
	
	//克隆全过程
	public ComplexListNode Clone(ComplexListNode root) {
		// TODO Auto-generated method stub
		
		//复制N’节点到N的next
		CloneNodes(root);
		//连接N‘节点的sibling节点到S'  其中S' = S.next
		ConnectSiblingNodes(root);
		//重新将链表连接,奇数个为原链表,偶数个为复制的链表
		return ReconnectNodes(root);
		
	}



	//复制N'节点到N的next指针
	public void CloneNodes(ComplexListNode root) {
		if(root == null) {
			return ;
		}
		
		ComplexListNode tempNode = root;
		
		//只要tempNode不为空,就复制N记作N',并将其next指针指向N'
		while(tempNode != null) {
			//克隆的N'
			ComplexListNode cloneNode = new ComplexListNode(tempNode.val);
			/////////////首先将cloneNode的本身连接好(N')
			cloneNode.next = tempNode.next;
			cloneNode.sibling = null; 
			////////然后再将N'连接到N的next   
			////////这样可以避免在声明一个对象,进行存储下一节点
			tempNode.next = cloneNode;
			tempNode = cloneNode.next;
		}
		
		
		
		
	}
	
	
	//将sibling指针S',将N'的sibling指针连接上,其中S'=S.next
	public void ConnectSiblingNodes(ComplexListNode root) {
		ComplexListNode tempNode = root;
		
		while(tempNode != null) {
			//cloneNode指向克隆节点N'
			ComplexListNode cloneNode = tempNode.next;
			//只有当N的sibling节点不为空的时候,才将N'指向S’(其中S'= S.next)
			if(tempNode.sibling != null) {
				cloneNode.sibling = tempNode.sibling.next;
			}
			tempNode = cloneNode.next;    //////
		}
		
	}
	
	

	
	//重新将链表连接,奇数个相连为原链表,偶数个相连为复制的链表
	public ComplexListNode ReconnectNodes(ComplexListNode root) {
		// TODO Auto-generated method stub
		//root为原链表的表头
		//oriNode为原链表的移动指针   一直执行那个原链表的节点N
		ComplexListNode oriNode = root;
		//克隆的表头 不是移动指针
		ComplexListNode cloneRoot = null;
		//克隆链表的移动指针  一直指向克隆出的节点N'
		ComplexListNode cloneNode = null;
		
		////////原链表 A -> B
		////////复制链表 A' 
		if(oriNode != null) {
			cloneRoot = cloneNode = oriNode.next;
			oriNode.next = cloneNode.next;
			oriNode = oriNode.next;
		}
		////////////每次移动节点 原链表 B -> C
		////////////  (2个为一个单位)  复制链表   A' -> B'...
		while(oriNode != null) {
			cloneNode.next = oriNode.next;
			cloneNode = cloneNode.next;
			oriNode.next = cloneNode.next;
			oriNode = oriNode.next;

		}
		
		return cloneRoot;		
	}



}

猜你喜欢

转载自blog.csdn.net/weixin_43137176/article/details/89343028