【Java】 剑指offer(35) 复杂链表的复制

本文参考自《剑指offer》一书,代码采用Java语言。

更多:《剑指Offer》Java实现合集  

题目 

  请实现函数ComplexListNode* Clone(ComplexListNode* pHead),复制一个复杂链表。在复杂链表中,每个结点除了有一个m_pNext指针指向下一个点外,还有一个m_pSibling 指向链表中的任意结点或者nullptr。

思路

  思路1:先复制结点,用next链接,最后根据原始结点的sibling指针确定该sibling结点距离头结点的位置,从而对复制结点设置sibling指针。但是该思路对于n个结点的链表,每个结点的sibling都需要O(n)个时间步才能找到,所以时间复杂度为O(n^2)

  思路2:复制原始结点N创建N’,用next链接。将<N,N‘>的配对信息存放入一个哈希表中;在设置sibling时,通过哈希表,只需要用O(1)的时间即可找到复制结点的sibling。该方法的时间复杂度为O(n),但空间复杂度为O(n)。

  思路3:复制原始结点N创建N’,将N‘链接到N的后面;根据原始结点N的sibling可以快速设置N‘结点的sibling,最后将这个长链表拆分成原始链表和复制链表(根据奇偶位置)

测试算例 

  1.功能测试(sibling指向自己;链表只有一个结点;sibling指向null或者指向结点)

  2.特殊测试(头结点为null)

Java代码

//题目:请实现函数ComplexListNode* Clone(ComplexListNode* pHead),复
//制一个复杂链表。在复杂链表中,每个结点除了有一个m_pNext指针指向下一个
//结点外,还有一个m_pSibling 指向链表中的任意结点或者nullptr。

public class CopyComplexList {
	public class ComplexListNode {
	    int val;
	    ComplexListNode next = null;
	    ComplexListNode sibling = null;

	    ComplexListNode(int label) {
	        this.val = label;
	    }
	}

	/*
	 * 主程序(包含三步)
	 */
	public ComplexListNode cloneList(ComplexListNode head) {
		cloneNodes(head);  			//1.复制结点
		connectSiblingNodes(head);  //2.设置sibling
		return reconnectNodes(head);//3.拆分长链表
	}

	/*
	 * 第一步:复制每个结点,并插入到原始节点的后面
	 */
	private void cloneNodes(ComplexListNode head) {
		ComplexListNode pNode=head;
		while(pNode!=null) {
			ComplexListNode clonedNode=new ComplexListNode(pNode.val);
			clonedNode.next=pNode.next;
			pNode.next=clonedNode;
			pNode=clonedNode.next;
		}
	}

	/*
	 * 第二步:根据原结点的sibling,设置复制结点的sibling
	 */
	private void connectSiblingNodes(ComplexListNode head) {
		ComplexListNode pNode=head;
		while(pNode!=null) {
			if(pNode.sibling!=null)	//必须考虑到siblingNode==null的情况!
				pNode.next.sibling=pNode.sibling.next;
			pNode=pNode.next.next;
		}
	}

	/*
	 * 第三步:将长链表拆分成原始链表和复制链表(根据奇偶位置)
	 */
	private ComplexListNode reconnectNodes(ComplexListNode head) {
		ComplexListNode clonedHead=null;
		ComplexListNode clonedNode=null;
		ComplexListNode pNode=head;
		if(head!=null) {
			clonedHead=head.next;
			clonedNode=pNode.next;
			pNode.next=clonedNode.next;
			pNode=pNode.next;	//提前将pNode指向下一个结点,方便判断是否为null
		}
		while(pNode!=null) {
			clonedNode.next=pNode.next;
			clonedNode=clonedNode.next;
			pNode.next=clonedNode.next;
			pNode=pNode.next;
		}
		return clonedHead;
	}
}

  

收获

  1.涉及链表结点操作,必须时刻注意对null的判断

  2.复制链表时,在原始结点后面直接插入复制结点,这种方法非常方便,有较高的时间效率,先记住,以后可能会遇到类似的应用

  3.查找时间复杂度为O(1),可以考虑使用哈希表。哈希表的应用要掌握。

更多:《剑指Offer》Java实现合集  

  

原文地址:https://www.cnblogs.com/yongh/p/9858421.html

时间: 2024-10-08 10:17:05

【Java】 剑指offer(35) 复杂链表的复制的相关文章

【剑指offer】复杂链表的复制

转载请注明出处:http://blog.csdn.net/ns_code/article/details/26154691 题目描述: 输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点). 输入: 输入可能包含多个测试样例,输入以EOF结束.对于每个测试案例,输入的第一行为一个整数n (1<=n<=1000):n代表将要输入的链表元素的个数.(节点编号从1开始).接下来有n个数,表示链表节点中的值.接下来有n个数Ti,Ti表示第i个节点的另

剑指offer (27) 复杂链表的复制

题目:请实现一个函数,复制一个复杂链表,在复杂链表中,每个结点除了有一个m_pNext指针指向下一个结点,还有一个m_pSibling指向链表中的任意节点或者NULL struct ComplexListNode { int m_nValue; ComplexListNode* m_pNext; ComplexListNode* m_pSibling; }; 方法一: step1. 复制原始链表的每一个节点,并用m_pNext链接起来 step2. 设置每个结点的m_pSibling指针 由于m

《剑指offer》复杂链表的复制

[ 声明:版权所有,转载请标明出处,请勿用于商业用途.  联系信箱:[email protected]] 题目链接:http://www.nowcoder.com/practice/f836b2c43afc4b35ad6adc41ec941dba?rp=2&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking 题目描述 输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向

[剑指offer] 25. 复杂链表的复制

题目描述 输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的head.(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空) 思路: 因为新链表也需要复制旧链表的random指针,而random指向的节点也有其next和random,需要保持链表的连贯,所以需要考虑先做出一条新链表,再去构建每一个节点的random节点,而如何同步random节点就是问题所在.有两种解决办法. 解法一:构建同一链表

剑指offer:复杂链表的复制

题目描述输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的head.(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空) # -*- coding: utf-8 -*- # @Time : 2019-07-05 15:52 # @Author : Jayce Wong # @ProjectName : job # @FileName : complexListNodeClone.py # @Bl

剑指Offer:删除链表的节点【18】

剑指Offer:删除链表的节点[18] 题目描述 在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针. 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5 题目分析 如上图所示,我们的定义了三个指针,其中第二.三个指针用于找到重复元素的第一个位置和最后一个位置的下一个位置,然后第一个指针的下一个指向三个指针,这样就跳过了重复元素. 但是编码发现后,还有两种情况欠考虑. 这种情况,刚开始,就是

剑指OFFER之反转链表(九度OJ1518)

题目描述: 输入一个链表,反转链表后,输出链表的所有元素.(hint : 请务必使用链表) 输入: 输入可能包含多个测试样例,输入以EOF结束.对于每个测试案例,输入的第一行为一个整数n(0<=n<=1000):代表将要输入的链表的个数.输入的第二行包含n个整数t(0<=t<=1000000):代表链表元素. 输出: 对应每个测试案例,以此输出链表反转后的元素,如没有元素则输出NULL. 样例输入: 5 1 2 3 4 5 0 样例输出: 5 4 3 2 1 NULL 解题思路:

剑指offer (35) 第一个只出现一次的字符 字符哈希表

题目:在字符串中找出第一个只出现一次的字符 题解分析:用空间换时间,使用哈希表,key为字符,value是该字符出现的次数 字符是一个长度为8的数据类型,因此总共只有256种可能,我们可以创建一个长为256的数组, 每个字符根据其ASCII码值作为数组的下标,即哈希表的key,而相应数组位置存储每个字符出现的次数,即哈希表的value char GetFirstOnce(const char* str) { assert(str != NULL); const int hashSize = 25

剑指offer——两个链表的公共节点

题目链接:输入两个链表,找出它们的第一个公共结点. 解题思路: 找出2个链表的长度,然后让长的先走两个链表的长度差,然后再一起走(因为2个链表用公共的尾部) 1 /* 2 public class ListNode { 3 int val; 4 ListNode next = null; 5 6 ListNode(int val) { 7 this.val = val; 8 } 9 }*/ 10 public class Solution { 11 public ListNode FindFir