每日一题(复制带随机指针的链表)
138. 复制带随机指针的链表 - 力扣(LeetCode)
思路:
由于每个链表还包含了一个random节点指向了链表中的随机节点,所以并不能直接照搬复制原链表。首先想到的暴力思路是复制一条新的链表。找到原链表的每个节点的random到该节点的相对举例。但是实际上操作起来更复杂。
这里提供另外一个思路:
- 第一步:创建新节点
在原链表的每个节点之后紧跟着复制一个节点,形成新老节点相间的局面,并且将原链表的每个节点的值赋值给其后创建的节点中,并且将新开辟的节点的random成员的值设置为NULL,如下图:
- 第二步:设置新节点random的值
创建一个cur指针指向原链表的第一个节点,再创建一个newhead指针指向cur的next;cur指针从head处出发,newhead从head->next处出发。开始遍历链表。这里有一个最重要的关系:当cur->random不为空时,(当cur->random的值为NULL时,则不做改动)满足:cur->random与cur的对应关系与newhead->random和cur->random->next的对应关系时一样的。
就可以根据这些对应关系修改新创建的节点的random的值。接着cur向后移动两步指向下一个原链表中的节点,newhead也向后走两步指向下一个新开辟的节点。如下图所示(红色的是random指针,绿色的是next指针):新节点之间的random的链接关系和原链表的random的链接关系并没有改变。
- 第三步:断开链表
创建三个指针cur1和cur2和newhead,cur1从head的next处开始遍历,cur2从head处开始遍历,newhead指针用于记录cur1的起始位置。将原链表的节点和新链表的节点各自分成一条链表。特别注意:这里的遍历迭代的顺序不得交换! 在两个指针向后更新的过程中,肯定是cur1->next先为NULL,当cur1->next为NULL时就退出循环,但是此时的cur2的next指针仍然指向的是新开辟的最后一个节点。所以在返回newhead之前,要将cur2->next置为NULL。
代码实现:
if(head==NULL) { return NULL; } struct Node* cur = head; struct Node* curNext = head; struct Node* newhead = head; //构造相间的节点 while(cur!=NULL) { curNext = cur->next; struct Node* newnode = (struct Node*)malloc(sizeof(struct Node)); if(newnode== NULL) return NULL; newnode->val = cur->val; newnode->random =NULL; //新节点链接在原节点之后 cur->next = newnode; newnode->next = curNext; cur = curNext; } cur = head; //复制各自的random while(cur!=NULL) { newhead = cur->next; if(cur->random!=NULL) { newhead->random = cur->random->next; } cur = cur->next->next; } //断开 newhead = head->next; struct Node* cur1 = newhead;//cur1用于遍历newnode struct Node* cur2 = head;//cur2用于遍历原链表的节点 while(cur1->next) { cur2->next = cur2->next->next; cur1->next = cur1->next->next; cur2 = cur2->next; cur1 = cur1->next; } //将cur2->next置空 cur2->next = NULL; return newhead;
完结
复制带随机指针的链表习题的分析就到这里啦,若有不足,欢迎评论区指正,下期见!