Copy List with Random Pointer复制带随机指针的链表

复制带随机指针的链表

给定一个链表,每个节点包含一个额外增加的随机指针,该指针可以指向链表中的任何节点或空节点。

要求返回这个链表的深度拷贝。 

这里参考了博文:

https://www.cnblogs.com/TenosDoIt/p/3387000.html(图画的很赞,这里借用了)

https://blog.csdn.net/sun20082567/article/details/36198817(图画的也很赞)

这道题由于链表带随机指针,如果每次遍历都去找每个节点的random指针,那么时间复杂度为O(n),如下图所示:


黑色表示random指针,蓝色表示next指针,未标出表示random指针为nullptr

首先通过原链表构建1'->2'->3'->4',然后对节点1',应该把1'的指针指向3',但是我们怎么得到1'->3'的映射关系呢?我们只有1->3的映射关系,所以直观的想法便是通过计数器来保存每一个节点的random指针是第几个节点,通过next遍历得到,对每一个节点都需要遍历一次原链表,时间复杂度是O(n^2),肯定time limited。所以需要换种思想:

算法一

由上述的提示,如果我们能找到原链表和新链表的映射关系,便可以直接构造新链表的random指针,所以我们需要一个map,

如下图所示:


map的映射关系为key:old_node,value:new_node,更新规则如下公式:

mapper[head_tmp] = new_head_tmp;

然后寻找random指针时用以下公式:

new_head_tmp->random = mapper[head_tmp->random];
代码如下,时间复杂度(O(n)),空间复杂度(O(n)):
    RandomListNode *copyRandomList(RandomListNode *head) {
	  if (!head) {
		  return head;
	  }
	  RandomListNode *head_tmp = head;
	  RandomListNode *new_head = new RandomListNode(head->label);
	  RandomListNode *new_head_tmp = new_head;
	  head_tmp = head_tmp->next;

	  map<RandomListNode *, RandomListNode *> mapper;
	  mapper[head] = new_head;
	  while (head_tmp) {
		  RandomListNode *new_node = new RandomListNode(head_tmp->label);
		  new_head_tmp->next = new_node;
		  new_head_tmp = new_head_tmp->next;
          mapper[head_tmp] = new_head_tmp;
		  head_tmp = head_tmp->next;
		  
	  }

	  head_tmp = head;
	  new_head_tmp = new_head;
	  while (head_tmp) {
		  if (head_tmp->random) {
			new_head_tmp->random = mapper[head_tmp->random];
		  }
		  head_tmp = head_tmp->next;
		  new_head_tmp = new_head_tmp->next;
	  }
	  return new_head;       
    }

算法2

我们把空间复杂度降为O(1),具体如下图所示:


第一次遍历原链表时把新节点加到原链表每个节点后面,

第二次遍历更新新节点的random指针,公式为:

new_head_tmp->random = old_head_tmp->random->next;

第三次遍历把原链表和新链表分开

代码如下:

    RandomListNode *copyRandomList(RandomListNode *head) {
	  if (!head) {
		  return head;
	  }
	  RandomListNode *old_head_tmp = head;
	  RandomListNode *new_head = new RandomListNode(head->label);
	  RandomListNode *new_head_tmp = new_head;
	  
	  new_head->next = head->next;
	  head->next = new_head;

	  old_head_tmp = old_head_tmp->next->next;
	  while (old_head_tmp) {
		  RandomListNode *new_node = new RandomListNode(old_head_tmp->label);
		  new_node->next = old_head_tmp->next;
		  old_head_tmp->next = new_node;
		  old_head_tmp = old_head_tmp->next->next;
	  }

	  old_head_tmp = head;
	  new_head_tmp = head->next;
	  while (old_head_tmp) {
		  if (old_head_tmp->random) {
			  new_head_tmp->random = old_head_tmp->random->next;
		  }
          old_head_tmp = old_head_tmp->next->next;
          
		  new_head_tmp = old_head_tmp!=nullptr?new_head_tmp->next->next:nullptr;
	  }

	  old_head_tmp = head;
	  new_head_tmp = head->next;
	  while (old_head_tmp) {
		  old_head_tmp->next = old_head_tmp->next->next;
		  new_head_tmp->next = old_head_tmp->next != nullptr ? new_head_tmp->next->next : nullptr;
		  old_head_tmp = old_head_tmp->next;
		  new_head_tmp = new_head_tmp->next;
	  }
	  return new_head;      
    }

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值