1.题目
输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针random指向一个随机节点),请对此链表进行深拷贝,并返回拷贝后的头结点。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)。 下图是一个含有5个结点的复杂链表。图中实线箭头表示next指针,虚线箭头表示random指针。为简单起见,指向null的指针没有画出。
2.解法
2.1 链表结构
class RandomListNode {
int label;
RandomListNode next = null;
RandomListNode random = null;
RandomListNode(int label) {
this.label = label;
}
}
2.2 解法1:让每个链表复制一次
每个链表的身后都复制一个新节点copy
。
然后复制random指向,因为每个复制的节点都在原始节点的身后,所以根据位置关系能够立即得知。
最后解离,奇数节点是原链表,偶数节点是新链表。
public RandomListNode Clone(RandomListNode pHead) {
if (pHead == null) return null;
RandomListNode original = pHead;
//复制,形成AA'->BB'->CC'的形式
while (original != null) {
RandomListNode copy = new RandomListNode(original.label);
copy.next = original.next;
original.next = copy;
original = copy.next;
}
//利用结构,复制random
original = pHead;
RandomListNode newP = pHead.next;
while (original != null ) {
newP.random = original.random==null?null:original.random.next;
original = original.next==null?null:original.next.next;
newP = newP.next==null?null:newP.next.next;
}
//解离
RandomListNode head = pHead.next;
original = pHead;
newP = pHead.next;
while (original != null ) {
original.next = original.next==null?null:original.next.next;
newP.next = newP.next==null?null:newP.next.next;
original = original.next;
newP = newP.next;
}
return head;
}
2.3 解法2:一次遍历+map
在第一次遍历原链表时,就复制一次,此时只复制next元素,并将原始节点和复制节点的映射关系用map存储。
在第二次时,根据random关系从map中查找。
public RandomListNode Clone(RandomListNode pHead) {
Map<RandomListNode,RandomListNode> map = new HashMap<>();
RandomListNode dummy = new RandomListNode(-1);
RandomListNode newp = dummy;
RandomListNode p = pHead;
while (p!=null){
RandomListNode node = new RandomListNode(p.label);
newp.next = node;
newp = newp.next;
map.put(p,newp);
p = p.next;
}
for(Map.Entry<RandomListNode,RandomListNode> entry:map.entrySet()){
if(entry.getKey().random==null) continue;
entry.getValue().random = map.get(entry.getKey().random);
}
return dummy.next;
}
总结
这道题有一定的复杂,需要两次处理。
算法系列在github上有一个开源项目,主要是本系列博客的demo代码。https://github.com/forestnlp/alg
如果您对软件开发、机器学习、深度学习有兴趣请关注本博客,将持续推出Java、软件架构、深度学习相关专栏。
您的支持是对我最大的鼓励。