剑指OFFER-复杂链表的复制

剑指OFFER-复杂链表的复制

  • Question
  • Solution
    • 储存random
    • 查找已存在的结点
    • 复制并拆分

Question

输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的head。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)
关键词:链表 指针

Solution

储存random

将链表拆成正常顺序的list和对应random指针的map。然后复制这个list和map得到新的链表
时间复杂度:O(N)
空间复杂度:O(N)

  • Python
class Solution:
    def Clone(self, pHead):
        lian = []
        biao = {}
        
        p = pHead
        # 复制链表,此时list里仍是旧链表
        while p:
            lian.append(p)
            p = p.next
        # 得到每个节点的random节点index
        p = pHead
        i = 0
        while p:
            if p.random:
                biao[i] = lian.index(p.random)
            else:
                biao[i] = -1
            p = p.next
            i += 1
        # new一个新的链表    
        new_lian = [RandomListNode(p.label) for p in lian]
        # 遍历更新新链表的random和next关系
        for i in range(len(new_lian)):
            if i < len(new_lian) - 1:
                new_lian[i].next = new_lian[i+1]
            if biao[i] != -1:
                new_lian[i].random = new_lian[biao[i]]
        return new_lian[0] if new_lian else None
  • C++

查找已存在的结点

利用map查找(O(1))next和random节点是否已经存在,不存在建立新的节点并且更新map,存在直接映射到已存在的节点。
时间复杂度:O(2N)
空间复杂度:O(N)

  • Python
class Solution:
    def Clone(self, pHead):
        if not pHead:
            return None
        
        biao = {}
        p = pHead
        # 定义map中原节点指向新的节点,注意在python中list的查找是O(N),而dict是O(Nlog(N)),另外set是O(log(N))但是无法保存映射关系
        biao[p] = RandomListNode(p.label)
        new_p = biao[p]
        new_head = new_p
        
        while p:
            if p.next:
            	# 判断next节点是否已经建立过(在map中存在)
                if p.next not in biao:
                    biao[p.next] = RandomListNode(p.next.label)
                new_p.next = biao[p.next]
            if p.random:
                if p.random not in biao:
                    biao[p.random] = RandomListNode(p.random.label)
                new_p.random = biao[p.random]
            p = p.next
            new_p = new_p.next
        return new_head
  • C++
//链接:https://www.nowcoder.com/questionTerminal/f836b2c43afc4b35ad6adc41ec941dba?answerType=1&f=discussion

HashMap<RandomListNode, RandomListNode> hashMap = new HashMap<>();
public RandomListNode Clone(RandomListNode pHead) {
    if (pHead == null)
        return null;
    RandomListNode randomListNode = new RandomListNode(pHead.label);
    hashMap.put(pHead, randomListNode);
 
    //移动的指针
    RandomListNode temp = randomListNode ;
    RandomListNode cur = pHead;
 
    while (cur != null) {
    //为next 节点赋值
        if (cur.next != null) {
            if (!hashMap.containsKey(cur.next))
                hashMap.put(cur.next, new RandomListNode(cur.next.label));
            temp.next = hashMap.get(cur.next);
        }
       //为random 节点赋值
        if (cur.random != null) {
            if (!hashMap.containsKey(cur.random))
                hashMap.put(cur.random, new RandomListNode(cur.random.label));
            temp.random = hashMap.get(cur.random);
        }
        //移动指针
        cur = cur.next;
        temp = temp.next;
    }
    return randomListNode;
    }

复制并拆分

在每个原节点后面复制新的节点,例如原A->新A->原B->新B->…,遍历两次分别更新新节点的next和random指向,最后拆出新节点形成新链表。
时间复杂度:O(2N)
空间复杂度:O(2N)

  • Python
class Solution:
    def Clone(self, pHead):
        if not pHead:
            return None
        # 在原节点后面加上新节点,并得到新的next关系
        p = pHead
        while p:
            temp = p.next
            clone = RandomListNode(p.label)
            p.next = clone
            clone.next = temp
            p = temp
        # 对所有新节点加上其random节点
        p = pHead
        while p:
            if p.random:
                p.next.random = p.random.next # 注意此时的random其实是原来random的复制节点,也就是random.next而不是random
            p = p.next.next
        #拆分新节点,注意末尾节点的next=None?判断
        new_head = pHead.next
        p = pHead
        while p:
            clone = p.next
            p.next = clone.next
            p = p.next
            if clone.next:
                clone.next = p.next
            
        return new_head
  • C++
// 链接:https://www.nowcoder.com/questionTerminal/f836b2c43afc4b35ad6adc41ec941dba?answerType=1&f=discussion

public class Solution {
    public RandomListNode Clone(RandomListNode pHead) {
        if(pHead == null) {
            return null;
        }
 
        RandomListNode currentNode = pHead;
        //1、复制每个结点,如复制结点A得到A1,将结点A1插到结点A后面;
        while(currentNode != null){
            RandomListNode cloneNode = new RandomListNode(currentNode.label);
            RandomListNode nextNode = currentNode.next;
            currentNode.next = cloneNode;
            cloneNode.next = nextNode;
            currentNode = nextNode;
        }
 
        currentNode = pHead;
        //2、重新遍历链表,复制老结点的随机指针给新结点,如A1.random = A.random.next;
        while(currentNode != null) {
            currentNode.next.random = currentNode.random==null?null:currentNode.random.next;
            currentNode = currentNode.next.next;
        }
 
        //3、拆分链表,将链表拆分为原链表和复制后的链表
        currentNode = pHead;
        RandomListNode pCloneHead = pHead.next;
        while(currentNode != null) {
            RandomListNode cloneNode = currentNode.next;
            currentNode.next = cloneNode.next;
            cloneNode.next = cloneNode.next==null?null:cloneNode.next.next;
            currentNode = currentNode.next;
        }
 
        return pCloneHead;
    }
}

你可能感兴趣的:(剑指OFFER-复杂链表的复制)