题目描述
请实现 copyRandomList 函数,复制一个复杂链表。在复杂链表中,每个节点除了有一个 next 指针指向下一个节点,还有一个 random 指针指向链表中的任意节点或者 null。
本题的两个解法都很有意思,mark一下
【重点学习第二种方法】
一、解法一:哈希表法
利用哈希表建立原链表head到新链表result的映射
第一趟遍历:
根据head的val创建新链表节点
将 head:result 的键值对放到HashMap中
第二趟遍历:
根据head等到他的random节点hRan
根据hRan得到他对应的value, 即新链表这个节点的 rRan
public Node copyRandomList(Node head) {
if (head == null) return null;
Map<Node, Node> map = new HashMap<>();
Node temp = head;
Node result = new Node(-1), cur = result;
while (head != null) {
cur.next = new Node(head.val);
map.put(head, cur.next);
cur = cur.next;
head = head.next;
}
cur = result.next;
while (temp != null) {
Node ran = temp.random;
if (ran != null) {
cur.random = map.get(ran);
}
cur = cur.next;
temp = temp.next;
}
return result.next;
}
时复:o(n) 两趟遍历
空复:o(n) 对每个节点建立一个映射哈希表
二、解法二:插入法
第一趟:在原链表head的每个节点cur的后面建立一个与cur等val的新节点node;
第二趟:根据cur.random 为node.random赋值为 cur.random.next
; 【注意判空】
第三躺:将cur与node的next指针还原【注意最后一个cur指针必须指向空】
public Node copyRandomList(Node head) {
if (head == null) return null;
Node result = null, cur = head;;
while (cur != null) {
Node temp = new Node(cur.val);
temp.next = cur.next;
cur.next = temp;
cur = temp.next;
}
cur = head;
result = head.next;
Node node = result;
while (cur != null) {
Node temp = cur.next.next;
if (cur.random != null) {
cur.next.random = cur.random.next;
}
cur = temp;
}
cur = head;
while (node.next != null) {
cur.next = node.next;
node.next = node.next.next;
node = node.next;
cur = cur.next;
}
cur.next = null;
return result;
}
时复:O(n) 三趟遍历
空复:O(1) 只需要几个辅助指针,算法原地工作。
总结
第一种解法中,为了不使得丢失新链表的头结点,使用一个伪头结点来记录。
并且循环中直接在node.next 创建新节点而不是在node处创建新节点,也是为了防止引用丢失。
第二种解法, 就像评论里面说的,像加了一条辅助线那么巧妙,可以说相当牛皮了。
解法参考至 k神