链表(四)复制含有随机指针节点的链表

题目:

一种特殊节点描述如下:

public static class Node{
		int value;
		Node next;
		Node rand;
		public Node(int a){
			this.value=a;
		}
	}

Node类中的value是节点值,next指针和正常单链表中next指针的意义一 样,都指向下一个节点。

rand指针是Node类中新增的指针,这个指针可 能指向链表中的任意一个节点,也可能指向null。

给定一个由Node节点类型组成的无环单链表的头节点head,请实现一个 函数完成这个链表中所有结构的复制,并返回复制的新链表的头节点。

 

思路:借助一个hashMap结构,将链表结构存入hashMap中,hashMap的key与value分别是原节点,新复制的节点。遍历一遍map一一对应复制,额外空间复杂度O(n)

代码:

public static Node CopyWithMap(Node head) {
			HashMap<Node,Node> map=new HashMap<Node,Node>();
			Node cur=head;
			while(cur!=null) {
				map.put(cur, new Node(cur.value));
				cur=cur.next;
			}
			cur=head;
			while(cur!=null) {
				map.get(cur).next= map.get(cur.next);
				map.get(cur).rand= map.get(cur.rand);
				cur=cur.next;
			}
			return map.get(head);
		}

 

进阶
不使用额外的数据结构,只用有限几个变量,且在时间复杂度为 O(N)内完成原问题要实现的函数。额外空间复杂度O(1)

思路:链表 A->B->C->D-null,遍历一遍,在每一个节点后面增加一个复制节点 Node' 链表变为A->A'->B->B'->C->C'->D->D'->null

然后进行复制rand节点的操作,(可以通过节点A找到节点 A.rand 而A.rand.next就是我们需要复制的随机节点)、

我的代码:

//方法二:额外空间O(1)
		public static Node CopyWithNode(Node head) {
			if(head==null)return null;
			Node cur=head;
			Node help=null;
			while(cur!=null) {
				 help=new Node(cur.value);
				help.next=cur.next;
				cur.next=help;
				cur=help.next;
			}
			
			cur=head;
			help=null;
			//复制随机节点
			while(cur!=null) {
				help=cur.next;
				help.rand= cur.rand==null?null:cur.rand.next;
				cur=cur.next.next;	
			}
			
			//指针指回来
			cur=head;
			help=head.next;
			Node res=head.next;
			while(cur!=null) {
				help=cur.next;
				cur.next=cur.next.next;
				
				help.next= help.next==null?help.next:help.next.next;
				cur=cur.next;
			}
			return res;
		}

左老师的代码:

public static Node copyListWithRand2(Node head) {
		if (head == null) {
			return null;
		}
		Node cur = head;
		Node next = null;
		// copy node and link to every node
		while (cur != null) {
			next = cur.next;
			cur.next = new Node(cur.value);
			cur.next.next = next;
			cur = next;
		}
		cur = head;
		Node curCopy = null;
		// set copy node rand
		while (cur != null) {
			next = cur.next.next;
			curCopy = cur.next;
			curCopy.rand = cur.rand != null ? cur.rand.next : null;
			cur = next;
		}
		Node res = head.next;
		cur = head;
		// split
		while (cur != null) {
			next = cur.next.next;
			curCopy = cur.next;
			cur.next = next;
			curCopy.next = next != null ? next.next : null;
			cur = next;
		}
		return res;
	}

(以下可忽略)

测试源码:

package ListNode;

import java.util.HashMap;

//复制含有随机指针节点的链表
public class CopyList {
	//链表结构
	public static class Node{
		int value;
		Node next;
		Node rand;
		public Node(int a){
			this.value=a;
		}
	}
	//方法一:额外空间O(n)借助一个hashMap结构,将链表结构存入hashMap中
    //hashMap的key与value分别是原节点,新复制的节点。遍历一遍map一一对应复制
		public static Node CopyWithMap(Node head) {
			//if(head==null)return null;
			HashMap<Node,Node> map=new HashMap<Node,Node>();
			Node cur=head;
			while(cur!=null) {
				map.put(cur, new Node(cur.value));
				cur=cur.next;
			}
			cur=head;
			while(cur!=null) {
				map.get(cur).next= map.get(cur.next);
				map.get(cur).rand= map.get(cur.rand);
				cur=cur.next;
			}
			return map.get(head);
		}
	//方法二:额外空间O(1)
		public static Node CopyWithNode(Node head) {
			if(head==null)return null;
			Node cur=head;
			Node help=null;
			while(cur!=null) {
				 help=new Node(cur.value);
				help.next=cur.next;
				cur.next=help;
				cur=help.next;
			}
			
			cur=head;
			help=null;
			//复制随机节点
			while(cur!=null) {
				help=cur.next;
				help.rand= cur.rand==null?null:cur.rand.next;
				cur=cur.next.next;	
			}
			
			//指针指回来
			cur=head;
			help=head.next;
			Node res=head.next;
			while(cur!=null) {
				help=cur.next;
				cur.next=cur.next.next;
				
				help.next= help.next==null?help.next:help.next.next;
				cur=cur.next;
			}
			return res;
		}
		
		public static void printRandLinkedList(Node head) {
			Node cur = head;
			System.out.print("order: ");
			while (cur != null) {
				System.out.print(cur.value + " ");
				cur = cur.next;
			}
			System.out.println();
			cur = head;
			System.out.print("rand:  ");
			while (cur != null) {
				System.out.print(cur.rand == null ? "- " : cur.rand.value + " ");
				cur = cur.next;
			}
			System.out.println();
		}
		
		public static void main(String[] args) {
			Node head = null;
			Node res1 = null;
			Node res2 = null;
			printRandLinkedList(head);
			res1 = CopyWithMap(head);
			printRandLinkedList(res1);
			res2 = CopyWithNode(head);
			printRandLinkedList(res2);
			printRandLinkedList(head);
			System.out.println("=========================");

			head = new Node(1);
			head.next = new Node(2);
			head.next.next = new Node(3);
			head.next.next.next = new Node(4);
			head.next.next.next.next = new Node(5);
			head.next.next.next.next.next = new Node(6);

			head.rand = head.next.next.next.next.next; // 1 -> 6
			head.next.rand = head.next.next.next.next.next; // 2 -> 6
			head.next.next.rand = head.next.next.next.next; // 3 -> 5
			head.next.next.next.rand = head.next.next; // 4 -> 3
			head.next.next.next.next.rand = null; // 5 -> null
			head.next.next.next.next.next.rand = head.next.next.next; // 6 -> 4

			printRandLinkedList(head);
			
			res1 = CopyWithMap(head);
			printRandLinkedList(res1);
			
			res2 = CopyWithNode(head);
			printRandLinkedList(res2);
			printRandLinkedList(head);
			System.out.println("=========================");

		}
	
	
		
	}

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值