Copy List with Random Pointer 复制有随机指针的链表@LeetCode

1 先画好图

2 注意可能形成环的情况,因此必须拆成3个循环来做


代码是按照 http://www.cnblogs.com/lautsie/p/3259724.html 的图来写的

一个单链表,其中除了next指针外,还有一个random指针,指向链表中的任意某个元素。如何复制这样一个链表呢?

通过next来复制一条链是很容易的,问题的难点在于如何恰当地设置新链表中的random指针。
很容易想到使用Hash表的做法,先依次遍历原链表,每经过一个节点X,开辟一个新节点Y,然后(key=X的地址,value=Y的地址)存入哈希表。第二次再遍历原链表,根据拓扑结构设置新的链表。需要O(n)的空间,时间也是O(n)。

如果不使用额外的空间,那么要想在旧链表和新链表的对应节点之间建立联系。就要利用链表中多余的指针。
O(n)复杂度,O(1)空间。如图所示,扫描两边即可。

需要复制的链表:

如图所示,ABCD是原来的链表,A’B’C’D’是复制的链表,第一遍扫描顺序复制next指针,把ABCD的next分别指向A’B’C’D’,将A’的next指针指向B,B’的next指针指向C,依次类推:

复制random指针: A’->random=A->random->next

恢复:A->next=A’->next;A’->next=A’->next->next;


再来一张示例图:


http://www.cnblogs.com/reynold-lei/p/3362614.html


package Level4;

import Utility.RandomListNode;

/**
 * Copy List with Random Pointer
 * 
 * A linked list is given such that each node contains an additional random
 * pointer which could point to any node in the list or null.
 * 
 * Return a deep copy of the list.
 * 
 */
public class S138 {

	public static void main(String[] args) {
		RandomListNode head = new RandomListNode(1);
		RandomListNode n2 = new RandomListNode(2);
		RandomListNode n3 = new RandomListNode(3);
		RandomListNode n4 = new RandomListNode(4);
		head.next = n2;
		n2.next = n3;
		n3.next = n4;
		head.random = n3;
		n2.random = n4;
		RandomListNode ret = copyRandomList(head);
		while(ret != null){
			System.out.println(ret.label);
			ret = ret.next;
		}
	}

	public static RandomListNode copyRandomList(RandomListNode head) {
		if(head == null){
			return null;
		}
		
		RandomListNode cur = head;
		RandomListNode copyHead = null;
		RandomListNode copyCur = null;
		
		// 形成图1
		while(cur != null){
			copyCur = new RandomListNode(cur.label);
			if(copyHead == null){
				copyHead = copyCur;
			}
			copyCur.next = cur.next;
			cur.next = copyCur;
			cur = cur.next.next;
		}
		
		// 形成图2
		// 注意此处必须要分成两个while loop而不能合并。
		// 如果合并,则在两对random指针互相形成环时会出错!
		cur = head;
		while(cur != null){
			cur.next.random = cur.random!=null ? cur.random.next : null;		// 设置copy节点的random指针
			cur = cur.next.next;
		}
		
		cur = head;
		while(cur != null){
			copyCur = cur.next;
			cur.next = cur.next.next;			// 恢复cur节点的next指针
			copyCur.next = cur.next!=null ? cur.next.next : null;		// 设置copy节点的next指针
			cur = cur.next;
		}
		
		return copyHead;
	}
}


记住图和三个步骤,然后细心

/**
 * Definition for singly-linked list with a random pointer.
 * class RandomListNode {
 *     int label;
 *     RandomListNode next, random;
 *     RandomListNode(int x) { this.label = x; }
 * };
 */
public class Solution {
    public RandomListNode copyRandomList(RandomListNode head) {
        if(head == null) {
            return null;
        }
        RandomListNode copyHead = null;
        RandomListNode copyCur = null;
        RandomListNode cur = head;
        
        while(cur != null) {
            copyCur = new RandomListNode(cur.label);
            if(copyHead == null) {
                copyHead = copyCur;
            }
            copyCur.next = cur.next;
            cur.next = copyCur;
            cur = cur.next.next;
        }
        
        cur = head;
        copyCur = copyHead;
        while(cur != null) {
            if(cur.random != null) {
                copyCur.random = cur.random.next;
            }
            cur = cur.next.next;
            if(copyCur.next != null) {
                copyCur = copyCur.next.next;
            }
        }
        
        cur = head;
        copyCur = copyHead;
        while(cur != null) {
            cur.next = cur.next.next;
            if(copyCur.next != null) {
                copyCur.next = copyCur.next.next;
            }
            cur = cur.next;
            copyCur = copyCur.next;
        }
        
        return copyHead;
    }
}




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值