题目
输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的head。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)
public class RandomListNode {
int val;
RandomListNode next = null;
RandomListNode random = null;
public RandomListNode(int val) {
this.val = val;
}
}
思路1
当我们访问一个结点时可能它的随机指针指向的结点还没有访问过,结点还没有创建;因为在我们还没有完全遍历一边链表的时候没有办法知道所有结点的地址。
先按照复制一个正常链表的方式复制,复制的时候把复制的结点做一个HashMap,以旧结点为key
,新节点为value
。这么做的目的是为了第二遍扫描的时候我们按照这个哈希表把结点的随机指针接上。总共要进行两次扫描,所以时间复杂度是O(2*n)=O(n)
。空间上需要一个哈希表来做结点的映射,所以空间复杂度也是O(n)
。
public RandomListNode copyRandomList1(RandomListNode head){
if(head == null) return head;
HashMap<RandomListNode,RandomListNode> map = new HashMap<RandomListNode,RandomListNode>();
//创建新链表
RandomListNode newHead = new RandomListNode(head.val);
//新节点和旧节点放到map里面
map.put(head,newHead);
RandomListNode pre = newHead;
RandomListNode node = head.next;
while(node!=null) {
//创建新节点,并把旧节点和新节点放到map里面
RandomListNode newNode = new RandomListNode(node.val);
map.put(node,newNode);
pre.next = newNode;
pre = newNode;
node = node.next;
}
node = head;
RandomListNode copyNode = newHead;
while(node!=null) {
//遍历旧链表,对应map拿到旧节点的随机指针然后赋给新节点的随机指针
copyNode.random = map.get(node.random);
copyNode = copyNode.next;
node = node.next;
}
return newHead;
}
思路2
如果不用map这个数据结构该怎么搞呢?还是要解决原结点和对应新结点之间的映射关系:
- 每新建一个结点就把该结点插入到原链表对应的原结点后;
- 上一步全部完成后,遍历原链表(2倍长度了),由于原结点和新结点之间是相邻的,因此只要
p->next
就可以通过原结点找到对应的新结点,这样就解决了这个映射关系,这一步确定随机指针; - 最后一步就是把加长后的链表拆分出来,这样即保证创建了新链表,也保证了原链表没有被破坏。
public RandomListNode CopyRandomList2(RandomListNode head){
if(head == null) return head;
RandomListNode node = head;
while(node!=null) {
RandomListNode newNode = new RandomListNode(node.val);
newNode.next = node.next;
node.next = newNode;
node = newNode.next;
}
node = head;
while(node!=null) {
if(node.random != null)
//这里node.random.next指向的是新节点,如果直接node.random就是连到原链表上了
node.next.random = node.random.next;
node = node.next.next;
}
RandomListNode newHead = head.next;
node = head;
while(node != null) {
RandomListNode newNode = node.next;
node.next = newNode.next;
if(newNode.next!=null)
newNode.next = newNode.next.next;
node = node.next;
}
return newHead;
}