剑指offer 35:复杂链表的复制 -- java、python实现

题目

  • 剑指offer 35.复杂链表的复制

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

示例 1:

在这里插入图片描述

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

示例 2:
在这里插入图片描述

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

示例 3:

在这里插入图片描述

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

示例 4:

输入:head = []
输出:[]

题解

法1 – java、python实现(HashMap / 字典 )

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

算法流程:

  1. 若头节点 head 为空节点,直接返回 nullnull ;
  2. 初始化: 哈希表 dic , 节点 cur 指向头节点;
  3. 复制链表:
    • 建立新节点,并向 dic 添加键值对 (原 p 节点, 新 p 节点) ;
    • p 遍历至原链表下一节点;
  4. 构建新链表的引用指向:
    • 构建新节点的 next 和 random 引用指向;
    • p 遍历至原链表下一节点;
  5. 返回值: 新链表的头节点 dic[p] ;
  • java代码
/*
// Definition for a Node.
class Node {
    int val;
    Node next;
    Node random;

    public Node(int val) {
        this.val = val;
        this.next = null;
        this.random = null;
    }
}
*/
class Solution {
    public Node copyRandomList(Node head) {
        if(head == null)
            return null;
        Node p = head; // p遍历链表
        Map<Node,Node> map = new HashMap<>();
        // 复制各节点,建立 原节点->新节点的映射(原新节点值相同)
        while(p != null){
            map.put(p,new Node(p.val));
            p = p.next;
        }
        p = head; 
        // 再次遍历列表,构建next和random指向
        while(p != null){
            // value.next   =    key.next
            map.get(p).next = map.get(p.next); 
            map.get(p).random = map.get(p.random);

            p = p.next;
        }
        // 打印新链表的头结点
        return map.get(head); //就是获取head对应的value

    }
}
  • python实现
"""
# Definition for a Node.
class Node:
    def __init__(self, x: int, next: 'Node' = None, random: 'Node' = None):
        self.val = int(x)
        self.next = next
        self.random = random
"""
class Solution:
    def copyRandomList(self, head: 'Node') -> 'Node':
        if not head:
            return 
        dict = {} 
        p = head # p用来遍历,取名cur挺好,表示current,目前在哪个位置
        # 第一次遍历,复制了各节点
        while p:
            dict[p] = Node(p.val) # 注意!这里的值也是节点,不是只有data数据
            p = p.next
        
        p = head # 从头开始,第二次遍历复制各节点的指向

        while p:
            dict[p].next = dict.get(p.next)
            dict[p].random = dict.get(p.random)

            p = p.next
        
        return dict[head]

法2 – 拼接 + 拆分(java/python)

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

在这里插入图片描述

  • java代码
class Solution {
    public Node copyRandomList(Node head) {
        if(head == null)
            return null;
        Node cur = head; // cur比p好听,代表指向的当前位置
        // 1. 拼接列表
        while(cur != null){
            Node tmp = new Node(cur.val); //生成新节点
            tmp.next = cur.next;
            cur.next = tmp.next;

            cur = cur.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; // 遍历也跳一个
            // 这两句是每次都在cur指向节点个pre指向节点进行跳一个
            pre = pre.next;
            cur = cur.next; 
        }
        pre.next = null; //单独处理原链表尾节点与原来相同
        
        return res; // 新链表的头结点
    }
}
  • python代码
"""
# Definition for a Node.
class Node:
    def __init__(self, x: int, next: 'Node' = None, random: 'Node' = None):
        self.val = int(x)
        self.next = next
        self.random = random
"""
class Solution:
    def copyRandomList(self, head: 'Node') -> 'Node':

        if not head:
            return
        cur = head
        # 1.复制节点,拼接链表
        while cur:
            tmp = Node(cur.val)
            tmp.next = cur.next
            cur.next = tmp
            cur = tmp.next
        # 2.给新节点添加random
        cur = head
        while cur:
            if cur.random:
                cur.next.random = cur.random.next
            cur = cur.next.next
        # 3.拆分链表
        cur = res = head.next
        pre = head
        while cur.next: # cur.next是原节点的下一个节点,这个节点存在就是还存在新的节点
            # 这两句是将链表拆分开
            pre.next = pre.next.next
            cur.next = cur.next.next
            # 这两句是向后继续循环
            pre = pre.next
            cur = cur.next
        
        pre.ne = None
        return res
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值