剑指Offer面试题26复杂链表的复制,面试题27二叉搜索树和双向链表(递归)

面试题26:复杂链表的复制

复制一个复杂链表,这个链表除了next指针,还有指向任意一个结点的sibling指针或空指针。

思路1:一个效率很低的方法:分两步,先复制一遍next链表,然后设置sibling指针。但由于不知道它指向的位置,所以要遍历一遍链表(在原链表中,从头走了几步,在新链表中,也走几步,这就能确定位置了),这样每个结点设置sibling都要经过O(n)步,总复杂度O(n^2)。

思路2:用空间换时间:和上边一样还是两步,区别在于第一步的时候要记录sibling的配对信息到一个哈希表中,这样第二步就能在O(1)时间内完成单个节点的sibling的设置。用O(n)的空间复杂度换来了O(n)的时间复杂度。

思路3:不用辅助空间实现O(n)的效率:三步,1,创建结点n的复制n',n指向n',n'指向下一个原始结点。2,设置sibling,原始结点指向谁,复制的结点就指向对应的复制。3,把这个长链表拆分成两个链表,完成复制。

本题Java实现如下:

public class ComplexList {
	//调用
	ComplexListNode clone(ComplexListNode head){
		cloneNodes(head);
		connectSiblingNodes(head);
		return reconnectNodes(head);
	}
	//第一步,复制结点
	void cloneNodes(ComplexListNode head){
		ComplexListNode p = head;
		while(p != null){
			ComplexListNode cloned = new ComplexListNode(p.value);
			cloned.next = p.next;
			p.next = cloned;
			p = cloned.next;
		}	
	}
	//第二步,设置sibling
	void connectSiblingNodes(ComplexListNode head){
		ComplexListNode p = head;
		while(p != null){
			if(p.sibling != null){
				p.next.sibling = p.sibling.next;
			}
			p = p.next.next;
		}
	}
	//第三步,拆分
	ComplexListNode reconnectNodes(ComplexListNode head){
		ComplexListNode p = head;
		ComplexListNode clonedHead = null;
		ComplexListNode tempHead = null;
		if(p != null){
			clonedHead = p.next;
			tempHead = clonedHead;
			p.next = clonedHead.next;
			p = p.next;
		}
		while(p != null){
			tempHead.next = p.next;
			tempHead = tempHead.next;
			p.next = tempHead.next;
			p = p.next;
		}
		return clonedHead;
	}
	//打印
	void print(ComplexListNode head){
		if(head == null ) return;
		while(head != null){
			System.out.println(head.value);
			if(head.sibling != null){
				System.out.println(head.sibling);
			}
			head = head.next;
		}
	}
	public static void main(String[] args) {
		ComplexList test = new ComplexList();
		ComplexListNode root=new ComplexListNode(0);
		ComplexListNode node1=new ComplexListNode(1);
		ComplexListNode node2=new ComplexListNode(2);
		ComplexListNode node3=new ComplexListNode(3);
		ComplexListNode node4=new ComplexListNode(4);
		root.next = node1;
		root.sibling = node2;
		node1.next = node2;
		node1.sibling = node4;
		node2.next = node3;
		node3.next = node4;
		test.print(root);
		test.print(test.clone(root));
	}
}
class ComplexListNode{
	int value;
	ComplexListNode next,sibling;
	ComplexListNode(int x){
		value = x;
	}
}

面试题27:二叉搜索树与双向链表(递归)

将二叉搜索树转换成一个排序的双向链表,要求不能创建新的结点,只能改变树中结点的指向。

思路:搜索树的中序遍历结果是排好序的,如果把它变成排序的双向链表,根结点一定和左子树里最大的结点相连,也一定和右子树最小的结点相连。然后对于左右子树的根结点,递归处理。

本题Java实现如下:

public class Convert {
	private BiTree convert(BiTree root){//这里返回二叉树表示的双向链表
		BiTree lastNode = null;//指向双向链表尾端(值最大的结点)
		BiTree headNode = convertNode(root,lastNode);//后边函数返回的是双向链表尾结点,我们需要头结点
		while(headNode != null && headNode.left != null){
			headNode = headNode.left;
		}
		return headNode;
	}
	private BiTree convertNode(BiTree root,BiTree lastNode){
		if(root == null){
			return null;
		}
		BiTree current = root;
		//按照中序遍历左根右的顺序来,左
		if(current.left != null){
			lastNode = convertNode(current.left, lastNode);
		}
		//根,此时lastNode应是左子树的最大值,与根相连后,根变成了新的lastNode
		current.left = lastNode;
		if(lastNode != null){
			lastNode.right = current;
		}
		lastNode = current;
		//右
		if(current.right != null){
			lastNode = convertNode(current.right, lastNode);
		}
		return lastNode;
	}
	public static void main(String[] args) {
		Convert test = new Convert();
		BiTree A1 = new BiTree(4);
		BiTree A2 = new BiTree(2);
		BiTree A3 = new BiTree(5);
		BiTree A4 = new BiTree(1);
		BiTree A5 = new BiTree(3);
		A1.left = A2;
		A1.right = A3;
		A2.left = A4;
		A2.right = A5;
		BiTree a = test.convert(A1);
		while(a != null){
			System.out.println(a.value);
			a = a.right;
		}
	}
}
class BiTree{
	int value;
	BiTree left,right;
	BiTree(int x){
		value = x;
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值