复杂链表的复制

 

 

 

题意:需要对链表进行深拷贝,要同时拷贝链表节点的val、next指针和random指针
题解一:

逐个拷贝每个链表节点到当前节点的后面,分三次遍历,每次遍历走两步,最后达到深拷贝的目的
1、第一次遍历原链表,逐个拷贝当前节点的值和next执行,(1->2->3变成1->1'->2->2'->3->3'

2、第二次遍历链表,逐个拷贝当前节点的random指针

3、第三次遍历链表,拆分原节点和copy节点

 

时间复杂度:O(n)

空间复杂度:O(1)

复制代码
func main() {
    node1 := &Node{Val: 1}
    node2 := &Node{Val: 2}
    node3 := &Node{Val: 3}

    node1.Next = node2
    node2.Next = node3
    node1.Random = node3 // Node 1's random points to Node 3
    node2.Random = node1 // Node 2's random points to Node 1
    node3.Random = nil
    copyNodeList(node1)
}
func copyNodeList(head *Node) *Node {
    if head == nil {
        return nil
    }

    // 1. 新生成copy节点放到原节点的后面,例如1->2->3这样的链表就变成了这样1->1'->2->2'->3->3'
    var cp *Node = nil
    for cur := head; cur != nil; cur = cur.Next.Next { // 因为是加上了copy节点,所以每次要移动2步
        cp = &Node{Val: cur.Val} // 此时拷贝节点的random指针都指向nil
        cp.Next = cur.Next
        cur.Next = cp
    }

    // 2. 随机指针的拷贝
    for cur := head; cur != nil; cur = cur.Next.Next {
        if cur.Random != nil { // random指针可能为空
            // cur.Next是cur的cp节点,所以cp节点的random指针是cur.random指针的cp节点,也就是cur.Random.Next
            cur.Next.Random = cur.Random.Next
        }
    }

    // 3. 拆分原节点 和 copy节点
    var temp *Node = nil
    newHead := head.Next
    for cur := head; cur != nil && cur.Next != nil; {
        temp = cur.Next      // copy节点
        cur.Next = temp.Next // 还原旧链表
        cur = temp           //拆分cp链表
    }
    //PrintList(head)
    //PrintList(newHead)
    return newHead
}

// PrintList 打印随机链表
func PrintList(head *Node) {
    cur := head
    var result [][]string
    for cur != nil {
        randomVal := "nil"
        if cur.Random != nil {
            randomVal = fmt.Sprintf("%d", cur.Random.Val)
        }

        result = append(result, []string{fmt.Sprintf("%d", cur.Val), randomVal})
        cur = cur.Next
    }
    fmt.Println(result)
}
复制代码

 

链接:https://leetcode.cn/problems/fu-za-lian-biao-de-fu-zhi-lcof/solutions/994069/jian-zhi-offer-35-fu-za-lian-biao-de-fu-1iud0/

 

解法二:随机链表拷贝的难点,在于如何拷贝next指针和random指针,相当于要同时维护两条链表的关系,解法一是将两个指针的关系分开遍历处理,逐个拷贝;另一种解法就是使用哈希表(map[*node]*node),直接映射旧节点到新节点的拷贝关系,知道当前拷贝节点对应的旧节点状态,就可以通过找旧节点,然后赋值,实现深拷贝

属于空间换时间的解法
时间复杂度:O(n)
空间复杂度:O(n)

复制代码
func copyRandomList(head *Node) *Node {
    if head == nil {
        return nil
    }
    // map中存的是(原节点->新节点)的映射关系,此时新节点只有val,指针并没有安排上
    nodeMap := make(map[*Node]*Node)
    for cur := head; cur != nil; cur = cur.Next {
        nodeMap[cur] = &Node{Val: cur.Val}
    }
    // 遍历原链表,根据map关系找到原节点状态,然后对拷贝节点进行赋值
    for cur := head; cur != nil; cur = cur.Next {
        nodeMap[cur].Next = nodeMap[cur.Next]
        nodeMap[cur].Random = nodeMap[cur.Random]
    }
    return nodeMap[head]
}
复制代码

 

posted @   知道了呀~  阅读(10)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
历史上的今天:
2018-12-24 hdu 2654 Be a hero
2018-12-24 hdu2588 GCD
点击右上角即可分享
微信分享提示