LeetCode 哈希表 138. 复制带随机指针的链表(链表,哈希表存位置)

 

 说到底就是要把给出的链表完整拷贝一份

如果仅仅需要拷贝正常的链表的话,只需要在循环中不断创建val和原始链表相同的节点并且将其连起来就行了。

加了这个random这个节点则较为复杂些。问题在于,random指向后是不连续的,这样在新的链表中没法遍历,说到底就是找不到指向的位置

很直觉的想到给节点编上号,这样就能通过节点找位置,通过位置找节点了

一开始的想法是建立两个Hashmap,

一个是<Node,Integer>,用于放原链表

一个是<Integer,Node>,用于放新的链表

这样是因为原链表需要通过节点找序号,新链表需要通过序号找节点

代码就写成了这样:

class Solution {

    public static Node copyRandomList(Node head) {
        HashMap<Node,Integer> hashMap1=new HashMap<Node,Integer>();
        HashMap<Integer,Node> hashMap2=new HashMap<Integer,Node>();
        int count=0;
        while(head!=null)
        {
            hashMap1.put(head,count);
            hashMap2.put(count,new Node(head.val));
            if(count!=0)
            {
                hashMap2.get(count-1).next=hashMap2.get(count);
            }

            head=head.next;
            count++;
        }
        hashMap1.put(null,count+1);
        hashMap2.put(count+1,null);
        head=hashMap1.keySet().iterator().next();
        count=0;
        while(head!=null)
        {
            Node no=hashMap2.get(hashMap1.get(head.random));
            hashMap2.get(count).random=no;
            count=count+1;
            head=head.next;
        }
        System.out.println(hashMap2.containsValue(hashMap2.get(2).random));
        return hashMap2.get(0);


    }

 LeetCode中出现了奇怪的bug,判定所有的新节点中的random都是null,但我调试了不是这样的,所以我觉得应该是bug吧。

但看了一个解法恍然大悟,搞什么节点-序号,序号-节点。直接节点对节点存在hashmap中就好了嘛。重要的是找位置

class Solution {
    public Node copyRandomList(Node head) {
        if(head==null) {
            return null;
        }
        //创建一个哈希表,key是原节点,value是新节点
        Map<Node,Node> map = new HashMap<Node,Node>();
        Node p = head;
        //将原节点和新节点放入哈希表中
        while(p!=null) {
            Node newNode = new Node(p.val);
            map.put(p,newNode);
            p = p.next;
        }
        p = head;
        //遍历原链表,设置新节点的next和random
        while(p!=null) {
            Node newNode = map.get(p);
            //p是原节点,map.get(p)是对应的新节点,p.next是原节点的下一个
            //map.get(p.next)是原节点下一个对应的新节点
            if(p.next!=null) {
                newNode.next = map.get(p.next);
            }
            //p.random是原节点随机指向
            //map.get(p.random)是原节点随机指向  对应的新节点 
            if(p.random!=null) {
                newNode.random = map.get(p.random);
            }
            p = p.next;
        }
        //返回头结点,即原节点对应的value(新节点)
        return map.get(head);
    }
}

最优的解法则又进一步,反正重要的是位置,只要通过旧节点能找到对应的新节点就行,所以直接把新节点插在旧节点后面

这样不用新建一个HashMap了,空间复杂度变为O1

class Solution {
    public Node copyRandomList(Node head) {
        if(head==null) {
            return null;
        }
        Node p = head;
        //第一步,在每个原节点后面创建一个新节点
        //1->1'->2->2'->3->3'
        while(p!=null) {
            Node newNode = new Node(p.val);
            newNode.next = p.next;
            p.next = newNode;
            p = newNode.next;
        }
        p = head;
        //第二步,设置新节点的随机节点
        while(p!=null) {
            if(p.random!=null) {
                p.next.random = p.random.next;
            }
            p = p.next.next;
        }
        Node dummy = new Node(-1);
        p = head;
        Node cur = dummy;
        //第三步,将两个链表分离
        while(p!=null) {
            cur.next = p.next;
            cur = cur.next;
            p.next = cur.next;
            p = p.next;
        }
        return dummy.next;
    }
}    

猜你喜欢

转载自www.cnblogs.com/take-it-easy/p/13183885.html