每日一练——两个单链表相交的一系列问题

来源:互联网 发布:学校机房还原软件 编辑:程序博客网 时间:2024/06/05 05:22
题意描述:
单链表可能有环,也可能无环。给定两个单链表的头节点head1和head2,这两个链表可能相交,也可能不相交。请实现一个函数,如果两个链表相交,请返回相交的第一个节点;如果不相交,返回null。
要求:

如果链表1的长度为N,链表2的长度为M,时间复杂度请达到O(N+M),额外空间复杂度请达到O(1)。

结构体如下:

struct node{        node(int val) : value(val), next(NULL){}        int value;        struct node *next;};

struct node *get_first_same_node(stack<struct node *> &stk1, stack<struct node *> &stk2){    struct node *intersect_node = NULL;    while (stk1.size() && stk2.size() && stk1.top() == stk2.top())    {        intersect_node = stk1.top();        stk1.pop();        stk2.pop();    }    return intersect_node;}struct node *no_loop(struct node *&head1, struct node *&head2){    stack<struct node *> stk1, stk2;    struct node *cur_node;    cur_node = head1;    while (cur_node)    {        stk1.push(cur_node);        cur_node = cur_node->next;    }    cur_node = head2;    while (cur_node)    {        stk2.push(cur_node);        cur_node = cur_node->next;    }    return get_first_same_node(stk1, stk2);}

struct node *both_loop(struct node *&head1, struct node *&loop1,                       struct node *&head2, struct node *&loop2){    //在进环前相交    if (loop1 == loop2)    {        stack<struct node *> stk1, stk2;        struct node *cur_node;        cur_node = head1;        while (cur_node != loop1)        {            stk1.push(cur_node);            cur_node = cur_node->next;        }        cur_node = head2;        while (cur_node != loop2)        {            stk2.push(cur_node);            cur_node = cur_node->next;        }        return get_first_same_node(stk1, stk2);//找到第一个相同的节点    }    //在进环后相交    else    {        return loop1;//or return loop2    }}

如何找出带环路的链表的第一个进环的节点?
假设进环前链表的长度为L,环形链表的长度是S,使用快慢指针,快的指针一次走两步,慢的指针一次走一步,那么他们必然在环路上相遇,假设相遇的节点离进环节点的距离是X, 那么必然有L + S + X = 2 * ( L + X),可以推出S = L + X, 从而推出L = S - X。重新将一个指针指向头节点,然后和之前的慢指针(从环路相遇点开始)以相同的速度向前走。最后必然会在进环节点处相遇。


 

//获取第一个进环的节点struct node *get_in_loop_node(struct node *&head){    if (head == NULL || head->next == NULL)    {        return NULL;    }    struct node *fast_node , *slow_node;    slow_node = head->next;    fast_node = head->next->next;    while (slow_node != fast_node)    {        if (fast_node->next == NULL || fast_node->next->next == NULL)        {            return NULL;        }                fast_node = fast_node->next->next;        slow_node = slow_node->next;    }    struct node *in_loop_node = head;    while (in_loop_node != slow_node)    {        in_loop_node = in_loop_node->next;        slow_node = slow_node->next;    }    return in_loop_node;}

综合以上几种情况,我们可以知道,如果两个链表都没有环路,那么用栈来处理;如果两个链表都有环路,但是在进环的节点一样,那么说明它们在进环前就相交,和第一种情况一样处理;如果两个链表都有环路,但是进环节点不一样,那么一定是在进环后相交,进环的两个节点均可认为是相交的节点;如果一个链表有环一个链表无环,那么这两个链表一定不会相交。

struct node * get_intersect_node(struct node *&head1, struct node *&head2){    if (head1 == NULL ||head2 == NULL)    {        return NULL;    }    struct node *loop1 = get_in_loop_node(head1);    struct node *loop2 = get_in_loop_node(head2);    //两个链表均无环路    if (loop1 == NULL && loop2 == NULL)    {        return no_loop(head1, head2);    }    //两个链表均有环路    if (loop1 != NULL && loop2 != NULL)    {        return both_loop(head1, loop1, head2, loop2);    }    //一个链表有环路,一个链表没有环路,必然不相交    return NULL;}

参考:

http://www.nowcoder.com/live/11/6/live


0 0