138. Copy List with Random Pointer [LeetCode]

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关系指向

第三步,分离两个链表。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

luuyiran

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值