zoukankan      html  css  js  c++  java
  • 剑指25.复杂链表的复制

    题目描述

    输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针random指向一个随机节点),请对此链表进行深拷贝,并返回拷贝后的头结点。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)
     

    思路

    思路1:先复制结点,用next链接,最后根据原始结点的random指针确定该random结点距离头结点的位置,从而对复制结点设置random指针。但是该思路对于n个结点的链表,定位每个节点的random都需要从链表头节点开始经过O(n)步才能找到,所以时间复杂度为O(n^2)。  (时间主要花费在定位节点的random上)
     
     
    思路2:复制原始结点N创建N’,用next链接。将<N,N'>的配对信息存放入一个哈希表中;在设置random时,通过哈希表,只需要用O(1)的时间即可找到复制结点的random。该方法的时间复杂度为O(n),但空间复杂度为O(n)。        (相当于空间换时间)
     
     
    思路3:不用辅助空间的情况下,实现O(n)的时间效率。该方法分为三个步骤。
    第一步:复制原始链表的任意节点N并创建新节点N',再把N'链接到N的后面

    第二步:把复制的节点的random指针指向被复制节点的random指针的下一个节点

    第三步: 拆分成两个链表,奇数位置为原链表,偶数位置为复制链表,注意复制链表的最后一个结点的next指针不能跟原链表指向同一个空结点None,next指针要重新赋值None(判定程序会认定你没有完成复制)

     

    解法1(对应思路3)

    /*
    public class RandomListNode {
        int label;
        RandomListNode next = null;
        RandomListNode random = null;
    
        RandomListNode(int label) {
            this.label = label;
        }
    }
    */
    public class Solution {
        public RandomListNode Clone(RandomListNode pHead) {
            if (pHead == null) return null;
            cloneNodes(pHead);             // 复制节点
            connectRandomNodes(pHead);     // 设置random
            return reconnectNodes(pHead);  // 拆分长链表
        }
        // 第一步:复制每个结点,并插入到原始节点的后面
        private void cloneNodes(RandomListNode pHead){
            RandomListNode currentNode = pHead;
            while (currentNode != null){
                RandomListNode cloneNode = new RandomListNode(currentNode.label);
                cloneNode.next = currentNode.next;
                cloneNode.random = null;
                currentNode.next = cloneNode;
    
                currentNode = cloneNode.next;
            }
        }
        // 第二步:根据原节点的random,设置复制节点的random
        private void connectRandomNodes(RandomListNode pHead){
            RandomListNode currentNode = pHead;
            while (currentNode != null){
                if (currentNode.random != null)
                    currentNode.next.random = currentNode.random.next; // 指向原始节点random指向的下一个节点
                currentNode = currentNode.next.next;
            }
        }
        // 第三步:将长链表拆分成原始链表和复制链表(根据奇偶位置)
        private RandomListNode reconnectNodes(RandomListNode pHead){
            RandomListNode currentNode = pHead;
            RandomListNode pCloneHead = pHead.next;
            while (currentNode != null){
                RandomListNode pCloneNode = currentNode.next;
                if (pCloneNode.next != null){
                    currentNode.next = pCloneNode.next;
                    pCloneNode.next = currentNode.next.next;
                }else{
                    currentNode.next = null;
                    pCloneNode.next = null;
                }
                currentNode = currentNode.next;
            }
            return pCloneHead;
        }
    }

    解法2(对应思路2)

    /*
    public class RandomListNode {
        int label;
        RandomListNode next = null;
        RandomListNode random = null;
    
        RandomListNode(int label) {
            this.label = label;
        }
    }
    */
    import java.util.HashMap;
    /*
       使用哈希表,时间复杂度O(N),额外空间复杂度O(N)
       需要2次遍历即可
     */
    public class Solution {
        public RandomListNode Clone(RandomListNode pHead) {
            if (pHead == null) return null;
            HashMap<RandomListNode,RandomListNode> map = new HashMap<RandomListNode, RandomListNode>();
            RandomListNode currentNode = pHead;
            // 第一次遍历,新建节点,将<N,N'>的配对信息放到Map中
            while (currentNode != null){
                map.put(currentNode, new RandomListNode(currentNode.label));
                currentNode = currentNode.next;
            }
    
            // 第二次遍历,设置复制节点的属性next和random
            currentNode = pHead;
            while (currentNode != null){
                RandomListNode cloneNode = map.get(currentNode);
                // 注意复制链表的最后一个结点的next指针不能跟原链表指向同一个空结点
                cloneNode.next = currentNode.next == null ? null : map.get(currentNode.next);
                cloneNode.random = currentNode.random == null ? null : map.get(currentNode.random);
                currentNode = currentNode.next;
            }
            return map.get(pHead);
        }
    }
  • 相关阅读:
    如何使用php实现首页和子页面之间的交互
    用php实现,打开哪个页面哪个页面就有默认的样式
    后台链接前台有关显示不显示
    上传文件的最大值,post传值的最大值得修改
    linux 操作系统的安装,本地登录及远程登录,vnc连接操作详细步骤
    滑动组件
    Numpy简介
    java对象序列化
    集合类操作需要注意的地方
    TreeMap详解
  • 原文地址:https://www.cnblogs.com/HuangYJ/p/13504149.html
Copyright © 2011-2022 走看看