• 每日一练leetcode


    offer 35.复杂链表的复制

    请实现 copyRandomList 函数,复制一个复杂链表。在复杂链表中,每个节点除了有一个 next 指针指向下一个节点,还有一个 random 指针指向链表中的任意节点或者 null。

    来源:力扣(LeetCode)

    输入:head = [[7,null],[13,0],[11,4],[10,2],[1,0]]
    输出:[[7,null],[13,0],[11,4],[10,2],[1,0]]

    输入:head = [[1,1],[2,1]]

    输出:[[1,1],[2,1]]

    输入:head = [[3,null],[3,0],[3,null]]

    输出:[[3,null],[3,0],[3,null]]

    提示:

    • -10000 <= Node.val <= 10000
    • Node.random 为空(null)或指向链表中的节点。
    • 节点数目不超过 1000 。

    此题是一个中等题,如何按照咱们之前的方法简单链表的复制,没有random指针,直接前插法或后插法复制新链表,而此题不同有一个random指针问题就在于我们如何处理这个指针,我们先看一下难点在哪

    class Solution {
        public Node copyRandomList(Node head) {
            Node cur = head;
            Node dum = new Node(0), pre = dum;
            while(cur != null) {
                Node node = new Node(cur.val); // 复制节点 cur
                pre.next = node;               // 新链表的 前驱节点 -> 当前节点
                // pre.random = "???";         // 新链表的 「 前驱节点 -> 当前节点 」 无法确定
                cur = cur.next;                // 遍历下一节点
                pre = node;                    // 保存当前新节点
            }
            return dum.next;
        }
    }
    

      绿色的地方就是我们的难点 如何处理呢?

    我们第一种方法就是HashMap

    利用哈希表的查询特点,考虑构建 原链表节点 和 新链表对应节点 的键值对映射关系,再遍历构建新链表各节点的 next 和 random 引用指向即可。

    算法流程:

    1.若头节点 head 为空节点,直接返回 nullnull ;
    2.初始化: 哈希表 dic , 节点 cur 指向头节点;
    3.复制链表:
    4.建立新节点,并向 dic 添加键值对 (原 cur 节点, 新 cur 节点) ;
    5.cur 遍历至原链表下一节点;
    6.构建新链表的引用指向:
    7.构建新节点的 next 和 random 引用指向;
    8.cur 遍历至原链表下一节点;
    9.返回值: 新链表的头节点 dic[cur] ;

    class Solution {
        public Node copyRandomList(Node head) {
            if(head == null) return null;
            Node cur = head;
            Map<Node, Node> map = new HashMap<>();
            // 3. 复制各节点,并建立 “原节点 -> 新节点” 的 Map 映射
            while(cur != null) {
                map.put(cur, new Node(cur.val));
                cur = cur.next;
            }
            cur = head;
            // 4. 构建新链表的 next 和 random 指向
            while(cur != null) {
                map.get(cur).next = map.get(cur.next);
                map.get(cur).random = map.get(cur.random);
                cur = cur.next;
            }
            // 5. 返回新链表的头节点
            return map.get(head);
        }
    }
    

      方法二:拼接+拆分

    考虑构建 原节点 1 -> 新节点 1 -> 原节点 2 -> 新节点 2 -> …… 的拼接链表,如此便可在访问原节点的 random 指向节点的同时找到新对应新节点的 random 指向节点。

    1.复制各节点,构建拼接链表:

    2.构建新链表各节点的 random 指向

    3.拆分原 / 新链表

    4.返回新链表的头节点 res 即可

    class Solution {
        public Node copyRandomList(Node head) {
            if(head == null) return null;
            Node cur = head;
            // 1. 复制各节点,并构建拼接链表
            while(cur != null) {
                Node tmp = new Node(cur.val);
                tmp.next = cur.next;
                cur.next = tmp;
                cur = tmp.next;
            }
            // 2. 构建各新节点的 random 指向
            cur = head;
            while(cur != null) {
                if(cur.random != null)
                    cur.next.random = cur.random.next;
                cur = cur.next.next;
            }
            // 3. 拆分两链表
            cur = head.next;
            Node pre = head, res = head.next;
            while(cur.next != null) {
                pre.next = pre.next.next;
                cur.next = cur.next.next;
                pre = pre.next;
                cur = cur.next;
            }
            pre.next = null; // 单独处理原链表尾节点
            return res;      // 返回新链表头节点
        }
    }
    

      

     
  • 相关阅读:
    ASP.NET MVC 3 Internationalization
    Windows 8学习笔记(十)Notification
    Windows 8学习笔记(十二)集合控件
    Windows 8学习笔记(七)Input输入设备
    【配置与安装】解决类似umount target is busy挂载盘卸载不掉问题
    【coredump】coredump 使用
    【C++调试】"./xxx: /lib64/libstdc++.so.6: version `CXXABI_1.3.9' not found (required by ./xxx)" 执行报错
    【配置与安装】CentOS7 多磁盘合成卷组并创建LVM,挂载到同一目录
    Unix 知识
    3D创作概念入门
  • 原文地址:https://www.cnblogs.com/nenu/p/15073725.html
Copyright © 2020-2023  润新知