138. Copy List with Random Pointer
/**************************************************************************
*
* 138. [Copy List with Random Pointer](https://leetcode.com/problems/copy-list-with-random-pointer/)
*
* A linked list of length n is given such that each node contains an additional random pointer,
* which could point to any node in the list, or null.
*
* Construct a deep copy of the list. The deep copy should consist of exactly n brand new nodes,
* where each new node has its value set to the value of its corresponding original node.
* Both the next and random pointer of the new nodes should point to new nodes in the copied list
* such that the pointers in the original list and copied list represent the same list state.
* None of the pointers in the new list should point to nodes in the original list.
*
**************************************************************************/
struct Node {
int val;
struct Node *next;
struct Node *random;
};
typedef struct Node NODE;
///
/// Solution 1: C
/// 1、先深拷贝,忽略random指针
/// 2、遍历原链表,确定每一个节点的random指向的节点位于链表位置,找到这个下标。
/// 3、遍历拷贝的链表,每一个节点random指向下标index位置的节点。
int findRandomPointIndex(NODE *head, NODE *cur) {
if (NULL == head || NULL == cur) return -1;
int index = 0;
NODE *p = cur->random;
if (NULL == p) return -1;
//printf("p->val: %d\n", p->val);
while (head) {
if (p == head)
break;
index++;
head = head->next;
}
//printf("index:%d\n", index);
return index;
}
NODE *indexOf(NODE *head, int index) {
for (int i = 0; i < index && head; i++, head = head->next);
return head;
}
NODE *copyRandomList(NODE *head) {
if (NULL == head)
return NULL;
NODE *res = (NODE *)calloc(1, sizeof(NODE));
res->val = head->val;
NODE *pre = res;
for (NODE *cur = head->next; cur;) {
NODE *node = (NODE *)calloc(1, sizeof(NODE));
node->val = cur->val;
pre->next = node;
cur = cur->next;
pre = node;
}
NODE *old = head;
NODE *new = res;
while (old && new) {
int randomIndex = findRandomPointIndex(head, old);
if (-1 == randomIndex)
new->random = NULL;
else
new->random = indexOf(res, randomIndex);
old = old->next;
new = new->next;
}
return res;
}
///
/// Solution 2: C
/// 1、在每一个节点后面插入一个新节点,此时链表长度为原来的2倍。
/// 2、跳跃遍历,修正上一步插入新节点的random指向关系。
/// 3、分离两个链表。
/// [ref](https://blog.csdn.net/MC_007/article/details/80474614)
NODE* copyRandomList(NODE *head) {
if (NULL == head)
return NULL;
for (NODE *cur = head; cur; ) {
NODE *node = (NODE *)calloc(1, sizeof(NODE));
node->val = cur->val;
node->next = cur->next;
cur->next = node;
cur = node->next;
}
for (NODE *cur = head; cur; ) {
if (cur->random)
cur->next->random = cur->random->next;
cur = cur->next->next;
}
NODE *ret = head->next;
for (NODE *cur = head; cur; ) {
NODE *copy_cur = cur->next;
NODE *new_cur = cur->next->next;
cur->next = new_cur;
cur = new_cur;
if (cur)
copy_cur->next = cur->next;
}
return ret;
}
///
/// test code
static void print(NODE *head) {
printf("================\n");
while (head) {
printf("%p [val:%d random[%2d]:%p\n", \
head, head->val, head->random ? head->random->val : -1, head->random);
head = head->next;
}
}
NODE *generateList() {
NODE *res = (NODE *)calloc(1, sizeof(NODE));
NODE *pre = res;
for (int i = 0; i < 5; i++) {
NODE *node = (NODE *)calloc(1, sizeof(NODE));
node->val = i + 1;
pre->next = node;
pre = node;
}
res->random = NULL; //-1
res->next->random = res; //0
res->next->next->random = res->next->next->next->next; //4
res->next->next->next->random = res->next->next; //2
res->next->next->next->next->random = res; //0
return res;
}
int main() {
NODE *list = generateList();
print(list);
NODE *copy = copyRandomList(list);
print(copy);
return 0;
}
Solution 2 的三次for循环示意图:
第一遍遍历,在原节点后面创建一个新节点,
第二遍遍历,复制新节点间的random关系指向
第三步,分离两个链表。