链表面试题总结(二)

来源:互联网 发布:网络思想政治教育总结 编辑:程序博客网 时间:2024/06/05 02:54

昨天总结了一部分基础的面试题,有兴趣的小伙伴可以戳链接去看看链表面试题总结(一)。今天想要总结的是链表面试题的升级部分,关于链表带环部分和相交部分。

常见的面试题目:

  • 合并两个有序链表, 合并后依然有序
  • 求两个已排序单链表中相同的数据
  • 判断单链表是否带环?若带环,求环的长度?求环的入口点?
  • 判断两个链表是否相交,若相交,求交点。(假设链表不带环)
  • 判断两个链表是否相交,若相交,求交点。(假设链表可能带环)

合并两个有序链表, 合并后依然有序

分析:首先它是一个有序链表,那么数据一定是规律的。我们创建新指针newHead用来保存合并后有序链表的头,用一个tail指针向后进行比较,指向新的节点。用tmp保存当前节点的信息,然后指针向后移动。直到其中一个链表被遍历完,直接用tail将另一个链表的后续部分链接起来。

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

SListNode* Merge(SListNode* l1, SListNode* l2)  //合并两个有序链表,合并后依然有序{    if (l1 == NULL) return l2;    if (l2 == NULL) return l1;    SListNode* newHead;    SListNode* tail;    SListNode* tmp;    if (l1->data < l2->data)        newHead = tail = l1;    else        newHead = tail = l2;    while ((l1!= NULL) && (l2 != NULL))    {        if (l1->data < l2->data)        {            tmp = l1;            l1 = l1->next;        }        else        {            tmp = l2;            l2 = l2->next;        }        tail->next = tmp;        tail = tmp;    }    if(l1) tail->next = l1;    else  tail->next = l2;    return newHead;}

求两个已排序单链表中相同的数据

分析:题目已经告诉我们是有序链表,所以一定要把这个条件用好。和上面的题目类似,直接对两个节点的数据进行比较,如果不相等,就向后移动,谁小就移动谁;如果相等,就直接打印此出来,直到遍历整个链表。由于较简单,就不画图说明了。

void UnionSet(SListNode* l1, SListNode* l2)   //求两个已排序单链表中相同的元素{    assert(l1 && l2);    while (l1 && l2)    {        if (l1->data < l2->data)            l1 = l1->next;        else if (l1->data > l2->data)            l2 = l2->next;        else        {            printf("%d  ", l1->data);            l1 = l1->next;            l2 = l2->next;        }    }}

判断单链表是否带环?若带环,求环的长度?求环的入口点?

1、判断单链表是否带环?

分析:先来判断一个链表是否带环,如果一个链表带环,它就没有尾节点,类似下图这种:

这里写图片描述

那么判断链表带环的问题就要从这里入手了,既然是一个环,那么肯定会在里面循环,所以就可以借鉴快慢指针问题了。定义一个快指针,一个慢指针,同时出发,如果可以相遇,那么就是环;如果不能相遇,则为非环链表。图示如下:

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

SListNode* IsCircle(SListNode* pHead)  //判断一个链表是否带环{    SListNode* fast, *slow;    fast = slow = pHead;    while (fast && fast->next)    {        fast = fast->next->next;        slow = slow->next;        if (fast == slow)        {            return slow;        }    }    return NULL;}

2、若带环,求环的长度

分析:如果判断为环了,定义一个计数器count,那么环的长度就是沿着这个环在走一遍,再次走到现在的位置时,count的值。

size_t GetCircle(SListNode* meetNode)  //如果带环,求环的长度{    assert(meetNode);    int count = 1;    SListNode* cur = meetNode->next;    while (cur != meetNode)    {        cur = cur->next;        ++count;    }    return count;}

3、求环的入口点

分析:既然已经能确定是环,而且在第1问中,将相遇点返回了,那么我们就可以利用数学知识来求解入口点这个问题了。在这里,要说的方法还是快慢指针,这个题换成数学题,就变成了求相遇问题。下面用图来解释一下。

这里写图片描述
这里写图片描述
这里写图片描述

(关于为什么是一个走两步,一个走一步的原因:既然是要相遇,如果快指针走三步,它每次会跳过两个节点,慢指针一次只能走一步,这就可能会错过。快指针每次走两步的话,只会跳过一个节点,无论如何后都会和慢指针相遇。)

SListNode* GetEnter(SListNode* pHead, SListNode* meetNode)  //求环的入口{    SListNode* cur = pHead;    assert(cur && meetNode);    while (cur && meetNode)    {        if (cur == meetNode)            return meetNode;        cur = cur->next;        meetNode = meetNode->next;    }    return NULL;}

判断两个链表是否相交,若相交,求交点。(假设链表不带环)

1、判断两个链表是否相交

分析:如果两个链表相交,那么它应该如下图所示。根据它的结构特点,我们可以发现,如果两个链表相交,它的尾节点一定是相同的。也就是说当两个链表的尾节点相同时,它们一定是相交的。

这里写图片描述

SListNode* IsUnion(SListNode* l1, SListNode* l2)  //判断是否相交{    assert(l1 && l2);    while (l1->next)        l1 = l1->next;    while (l2->next)        l2 = l2->next;    if (l1 == l2)        return l1;    return NULL;}

2、若相交,求交点

分析:在链表中的相交相遇问题,貌似比较优的解法都是和快慢指针有关的。当然求交点,也是一样的。假设,两个链表一样长,那么它们的相交的判断方法就是在某处这两个节点的信息相同。好了,现在假设我们知道这两个链表的长度,让较长的那个先走两个链表长度之差步,那么接下来的处理方式就和一样长的链表的处理方式一样了。
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

SListNode* GetMeetNode(SListNode* l1, SListNode* l2) //如果相交,求交点{    int len1 = 1;    int len2 = 1;    SListNode* cur1 = l1;    SListNode* cur2 = l2;    while (cur1->next)    {        cur1 = cur1->next;        ++len1;    }    while (cur2->next)    {        cur2 = cur2->next;        ++len2;    }    size_t k = abs(len1 - len2);    SListNode* longNode, *shortNode;    if (len1 > len2)    {        longNode = l1;        shortNode = l2;    }    else    {        longNode = l2;        shortNode = l1;    }    while (k--)    {        longNode = longNode->next;    }    while (longNode != shortNode)    {        longNode = longNode->next;        shortNode = shortNode->next;    }    return shortNode;}

判断两个链表是否相交,若相交,求交点。(假设链表可能带环)

其实这个题目和上面的那个比较相似,甚至说是上面的延伸。在这种情况下,我们只需要理清可能出现的情况,然后根据对应的情况进行分析。

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

上面这六种是满足题设要求的情况。每一种情况对应的判断条件都会有所不同,在这里就只和大家分享一下我对这个题的理解,不做详细的分析。

常见的链表面试题就这么多了,其实现在回头看这些题,解题的思路都略相像。可能不同的是,每个题想要的考察侧重点,学会分析题目的思路很重要,对题设要求一定要尽可能考虑到所有的情况。

0 0
原创粉丝点击